Repository navigation
Description
Verify latest release
- I verified that the issue exists in the latest pnpm release
pnpm version
No response
Which area(s) of pnpm are affected? (leave empty if unsure)
CLI
Link to the code that reproduces this issue or a replay of the bug
No response
Reproduction steps
Run outside any existing project or workspace:
cd "$(mktemp -d)"
pnpm --version
pnpm rt ls
cat package.jsonThe runtime command exits with status 1:
Error: ERR_PNPM_RUNTIME_UNKNOWN_SUBCOMMAND
× Unknown subcommand: ls
Nevertheless, package.json now exists and contains the default initialization template, including version 1.0.0, the placeholder test script, and license ISC.
Describe the Bug
Several commands create a default package.json merely while initializing command state, including read-only queries and invocations that subsequently fail argument or prerequisite validation.
For example, pnpm rt ls correctly reports ERR_PNPM_RUNTIME_UNKNOWN_SUBCOMMAND, but leaves a newly created package.json in the working directory.
This is broader than the runtime command. Successful queries and dedupe --check are also affected.
Other affected commands
Run each command in a separate fresh empty directory.
Results below are from 12.11.2. Every row creates package.json.
| Command | Result |
|---|---|
pnpm rt |
ERR_PNPM_RUNTIME_NO_SUBCOMMAND |
pnpm rt set |
ERR_PNPM_MISSING_RUNTIME_NAME |
pnpm rt set python |
ERR_PNPM_INVALID_RUNTIME_NAME |
pnpm why foo |
Exit 0 |
pnpm outdated |
Exit 0 |
pnpm audit |
ERR_PNPM_AUDIT_NO_LOCKFILE |
pnpm sbom --sbom-format cyclonedx |
ERR_PNPM_SBOM_NO_LOCKFILE |
pnpm dedupe --check |
ERR_PNPM_DEDUPE_CHECK_ISSUES |
pnpm import |
ERR_PNPM_LOCKFILE_NOT_FOUND |
pnpm patch |
ERR_PNPM_MISSING_PACKAGE_NAME |
pnpm patch-commit ./missing |
ERR_PNPM_INVALID_PATCH_DIR |
pnpm patch-remove |
ERR_PNPM_NO_PATCHES_TO_REMOVE |
pnpm remove |
ERR_PNPM_MUST_REMOVE_SOMETHING |
pnpm remove foo |
ERR_PNPM_CANNOT_REMOVE_MISSING_DEPS |
pnpm link ./missing |
Fails while reading the nonexistent target manifest |
There is also a successful lockfile-only reproduction:
cd "$(mktemp -d)"
cat > pnpm-lock.yaml <<'YAML'
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.: {}
YAML
pnpm fetch
cat package.jsonBoth tested v12 releases create package.json, although fetch is documented as ignoring the package manifest.
Starting again with only the same lockfile and running pnpm sbom --sbom-format cyclonedx also succeeds and creates the manifest. The generated SBOM then includes the scaffold's directory-derived name, version 1.0.0, and license ISC as root component metadata.
Suspected cause
In v12.11.2, State::load_or_create_manifest falls through to PackageManifest::create_if_needed outside a workspace. That function immediately writes the scaffold.
The runtime dispatcher initializes this state before validating the runtime subcommand. Several query commands use the same state initialization.
dedupe --check restores or removes the lockfile through its guard, but the newly created manifest remains.
link has a separate call to create_if_needed() before resolving the target manifest. Consequently, link ./missing also creates a root manifest in a workspace containing only pnpm-workspace.yaml with packages: [].
Scope and related work
PR #12919 already prevents the shared state initializer from scaffolding manifests inside workspaces. It does not cover ordinary non-workspace directories, and link bypasses that guard.
PR #12910 previously fixed scaffolding over an existing alternate manifest.
In the tested existing-manifest controls, JSON, JSON5, and YAML manifests remained unchanged. Commands such as list, licenses list, and rt --help did not create a manifest.
A fix likely needs to separate loading command state from persisting a new manifest, and also address link independently. Moving runtime validation earlier would fix the original reproduction but leave the successful read-only cases affected.
Regression coverage should include missing manifests outside workspaces, the rootless-workspace link case, and lockfile-only fetch/sbom, while preserving intentional manifest creation by commands that explicitly initialize or modify a package.
Expected Behavior
- Read-only queries and check mode should not create a project manifest.
- Invalid arguments and missing prerequisites in these examples should be rejected before creating a manifest.
- Fetching from a lockfile should not initialize a package.
- SBOM generation should not invent package metadata by persisting an initialization template.
Which Node.js version are you using?
24.20.0
Which operating systems have you used?
- macOS
- Windows
- Linux
If your OS is a Linux based, which one it is? (Include the version if relevant)
Fedora
Contributing a fix
- I am working on a fix
Activity
jatmn commentedon Oct 13, 2026
Opened draft PR #16915 for the reported cases. It keeps missing manifests in memory until a command explicitly saves one, delays
linkpersistence until target validation succeeds, and prevents lockfile-only SBOM generation from using initialization-template metadata. Successful init/add/install behavior and alternate manifest formats are preserved.All 806 selected CLI tests and the required local build, formatting, documentation, and lint checks passed. The PR is a draft while its CI status is checked.
Written by an agent (Codex, GPT-6).
fix(cli): avoid creating manifests for read-only and rejected commands
fix(cli): avoid creating manifests for read-only and rejected commands
fix(cli): avoid creating manifests for read-only and rejected commands (