Visitar URL original
`pnpm pack`/`pnpm publish` strip the `pnpm` field, so a config dependency's `pnpm.config` never reaches the registry (config includes, 12.15.0) · Issue #17210 · pnpm/pnpm · GitHub
Skip to content

pnpm pack/pnpm publish strip the pnpm field, so a config dependency's pnpm.config never reaches the registry (config includes, 12.15.0) #17210

Closed

Description

@kirillgroshkov

Verify latest release

  • I verified that the issue exists in pnpm 12.15.0, the first release that ships config includes (latest is 12.14.0, which does not have the feature yet).

pnpm version

12.15.0

Which area(s) of pnpm are affected?

CLI (pack / publish), config dependencies / config includes

Link to the code that reproduces this issue or a replay of the bug

Inline below: two files, two commands.

Reproduction steps

Create a config dependency exactly as documented in Settings from config dependencies:

package.json

{
  "name": "@acme/pnpm-policy",
  "version": "1.0.0",
  "pnpm": { "config": "./config.yaml" },
  "files": ["config.yaml"]
}

config.yaml

trustPolicy: no-downgrade

Then:

pnpm pack
tar -xzOf acme-pnpm-policy-1.0.0.tgz package/package.json

Output:

{
  "name": "@acme/pnpm-policy",
  "version": "1.0.0",
  "files": [
    "config.yaml"
  ]
}

The pnpm field is gone from the manifest that gets published. pnpm publish goes through the same exporter, so the package on the registry has no pnpm.config either.

Variants, same result:

  • pnpm pack --skip-manifest-obfuscation keeps packageManager but still drops pnpm (as its docs say: "The pnpm-specific pnpm field is still omitted").
  • Moving it to publishConfig: { "pnpm": { "config": "./config.yaml" } } does not help: pnpm is not in the publishConfig hoist whitelist, so it stays nested under publishConfig.

Describe the Bug

pnpm/crates/exportable-manifest/src/create.rs removes the pnpm key unconditionally when building the exportable manifest: omit_keys(original, &["scripts", "packageManager", "pnpm"]) by default, and omit_keys(original, &["pnpm"]) under skip_manifest_obfuscation.

That was harmless while pnpm only carried project settings, which v11+ no longer reads from package.json anyway. Since #16967, pnpm.config is the only way a config dependency can expose its settings YAML, and pnpm reads it from the installed package's package.json. A config dependency published with pnpm publish therefore arrives on the registry without pnpm.config, and a consumer that delegates settings to it under include cannot load them (the PR describes this as failing closed with ERR_PNPM_CONFIG_DEPENDENCY_SETTINGS_UNAVAILABLE).

The e2e coverage uses a pre-built registry fixture (pnpr/.fixtures/packages/@pnpm.e2e/pnpm-policy/1.0.0), so the publish path of a config dependency is not exercised by tests. In practice, a settings-carrying config dependency can currently only be published with a tool that keeps the field, which conflicts with the feature's own docs.

Expected Behavior

pnpm pack / pnpm publish keep pnpm.config in the exported manifest. Retaining just that sub-key and dropping the rest of the pnpm object would preserve the existing obfuscation of legacy project settings. Alternatively, the config includes docs should state that such packages must not be published with pnpm publish.

Which Node.js version are you using?

24.22.1

Which operating systems have you used?

  • macOS
  • Windows
  • Linux

Activity

  1. github-actions commented on Oct 21, 2026

    @github-actions
    Contributor

    @kirillgroshkov, are you planning to open a pull request for this? If so, reply here and a maintainer will assign the issue to you, so nobody else starts on the same fix.

  2. kirillgroshkov commented on Oct 21, 2026

    @kirillgroshkov
    Author

    Not planning to open a PR for this one, I don't have a Rust setup for the repo at hand. Leaving it to a maintainer.

    In case it helps, the fix looks small. In pnpm/crates/exportable-manifest/src/create.rs, publication_fields could keep just the config entry of pnpm after the existing omit_keys calls, in both obfuscation modes (untested sketch):

    fn publication_fields(original: &Map<String, Value>, skip_obfuscation: bool) -> Map<String, Value> {
        let mut publish = if skip_obfuscation {
            omit_keys(original, &["pnpm"])
        } else {
            let mut publish = omit_keys(original, &["scripts", "packageManager", "pnpm"]);
            if let Some(scripts) = original.get("scripts").and_then(Value::as_object) {
                publish.insert("scripts".to_string(), Value::Object(omit_keys(scripts, PREPUBLISH_SCRIPTS)));
            }
            publish
        };
        // A config dependency names its settings file in `pnpm.config` (config includes),
        // and pnpm reads it from the installed package.json. Keep that one entry,
        // the rest of `pnpm` stays obfuscated.
        if let Some(config) =
            original.get("pnpm").and_then(Value::as_object).and_then(|pnpm| pnpm.get("config"))
        {
            let mut pnpm = Map::new();
            pnpm.insert("config".to_string(), config.clone());
            publish.insert("pnpm".to_string(), Value::Object(pnpm));
        }
        publish
    }

    The two existing tests in create/tests.rs (obfuscation_strips_pnpm_internal_fields, skip_obfuscation_keeps_scripts_and_package_manager) keep passing since their fixture only has pnpm.overrides. A new test with "pnpm": { "config": "./config.yaml", "overrides": {} } would assert that out["pnpm"] equals { "config": "./config.yaml" } in both modes. The module doc comment and the --skip-manifest-obfuscation sentence in pnpm/docs/cli/publish.md ("The pnpm-specific pnpm field is still omitted") would need the same exception.

  3. zkochan commented on Oct 21, 2026

    @zkochan
    Member

    you don't need a rust setup. "pnpm install" should install the rust toolchain as well if all works well.

  4. zkochan commented on Oct 21, 2026

    @zkochan
    Member

    Opened #17213 to fix this.

    The PR updates publication_fields in pnpm/crates/exportable-manifest/src/create.rs to retain pnpm.config in the exported manifest (both by default and under --skip-manifest-obfuscation) while continuing to strip the rest of the pnpm object, and updates the pack/publish documentation and tests. This covers the full issue.


    Authored by Antigravity (Gemini 4 Argon)

  5. added a commit that references this issue on Oct 21, 2026
    7ef0e9d
  6. added a commit that references this issue on Nov 3, 2026
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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions