Skip to content

pacquet: pnpm.overrides not applied during fresh-lockfile resolution #12275

Description

@zkochan

Summary

pacquet does not apply pnpm.overrides during fresh-lockfile resolution. The override set is recorded in the lockfile's overrides: section, but the overridden versions are never substituted into the resolved dependency graph, so a fresh pacquet install resolves overridden dependencies to their un-overridden versions. This affects all override forms — plain version pins, npm: aliases, and catalog: values — not just one. Surfaced while working the lockfile-parity npm: alias slice (#12266).

Reproduction

// package.json
{ "dependencies": { "js-yaml": "^4.0.0" } }
# pnpm-workspace.yaml
overrides:
  js-yaml: 4.0.0
pacquet install --lockfile-only   # resolves js-yaml@4.2.0  (override ignored)
pnpm   install --lockfile-only    # resolves js-yaml@4.0.0  (override applied)

Same divergence with a transitive consumer (write-yaml-file@5.0.0js-yaml) and with npm:/catalog: override values:

override pnpm pacquet
js-yaml@^4.0.0: 4.0.0 4.0.0 4.2.0
js-yaml@^4.0.0: npm:@zkochan/js-yaml@0.0.11 @zkochan/js-yaml@0.0.11 4.2.0
js-yaml@^4.0.0: 'catalog:' (→ npm:@zkochan/js-yaml@0.0.11) @zkochan/js-yaml@0.0.11 + expanded in overrides: 4.2.0 + literal 'catalog:' in overrides:

Root cause

VersionsOverrider (pacquet-package-manager/src/overrides.rs) correctly rewrites a manifest's deps and is unit-tested — but it is only invoked in check_lockfile_freshness (install.rs:~1256), against a cloned root manifest, for the frozen-path specifier comparison. The fresh-resolution path (install_with_fresh_lockfile) never applies it: its only resolver manifest hook is the packageExtensions hook (into_manifest_hook), and the importer manifest handed to the resolver is pristine.

pnpm applies overrides via the readPackage hook (createVersionsOverrider), which runs on every resolved manifest, so overrides take effect on direct and transitive deps alike.

Fix direction

Thread the override-applying hook into the fresh resolver as a manifest hook (composed with the existing packageExtensions hook), so it rewrites every resolved manifest transitively — matching pnpm's readPackage flow. Two dependent symptoms then resolve too:

  • catalog:-valued overrides expand to their concrete spec in the lockfile overrides: section (currently written literally as 'catalog:'), since the resolved override map is used.
  • Transitively-overridden deps (e.g. write-yaml-filejs-yaml) pick up the override.

The catalog-snapshot half of category 2 (aliased entries dropped from catalogs:) is fixed separately in #12274.


Written by an agent (Claude Code, claude-opus-4-8).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions