Visitar URL original
Read-only and rejected commands unexpectedly create package.json in directories without a manifest · Issue #16907 · pnpm/pnpm · GitHub
Skip to content

Read-only and rejected commands unexpectedly create package.json in directories without a manifest #16907

Closed

Description

@silverling

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.json

The 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.json

Both 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

  1. added theissue type on Oct 13, 2026
  2. jatmn commented on Oct 13, 2026

    @jatmn
    Contributor

    Opened draft PR #16915 for the reported cases. It keeps missing manifests in memory until a command explicitly saves one, delays link persistence 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).

  3. added a commit that references this issue on Oct 13, 2026
    ed652bf
  4. added a commit that references this issue on Oct 14, 2026
    26056ad
  5. added a commit that references this issue on Oct 14, 2026
    5ded3b3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions