#16431·pnpm

Range pin in devEngines.packageManager records the running pnpm in the lockfile without checking minimumReleaseAge, so switching to it fails for everyone else

Author: chekrdCreated Sep 30, 2026Updated Sep 30, 2026
Labelsarea: lockfilearea: supply chain securityarea: resolution

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)

No response

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

No response

Reproduction steps

package.json:

json
{
  "devEngines": {
    "packageManager": {
      "name": "pnpm",
      "version": "^12.7.0",
      "onFail": "download"
    }
  }
}

pnpm-workspace.yaml:

yaml
minimumReleaseAge: 4320 # 3 days
  1. Outside the project, make pnpm 12.8.1 the global pnpm (pnpm self-update 12.8.1). The global install doesn't use the project's settings, which is expected.

  2. In the project, remove node_modules and pnpm-lock.yaml and run pnpm install. It succeeds and writes this, with no warning or prompt about release age:

    yaml
    packageManagerDependencies:
      pnpm:
        specifier: ^12.7.0
        version: 12.8.1

    Nothing fails yet: the running pnpm is the locked version, so there is nothing to download.

  3. Simulate another contributor or CI. Outside the project, switch the global pnpm to a different version that still satisfies the range (pnpm self-update 12.7.0), and empty $PNPM_HOME/package-manager-store so 12.8.1 isn't cached.

  4. In the project, run:

    $ CI=true pnpm install --frozen-lockfile
    Error: ERR_PNPM_NO_MATURE_MATCHING_VERSION
    
      × adding a new package
      ╰─▶ 15 versions do not meet the minimumReleaseAge constraint:
            @pnpm/[email protected] was published at 2026-09-28T17:38:06.259Z, within the minimumReleaseAge cutoff (2026-09-27T12:01:01.750Z)
            ...
            [email protected] was published at 2026-09-28T17:38:17.288Z, within the minimumReleaseAge cutoff (2026-09-27T12:01:01.750Z)

    (exit code 1)

    pnpm --version only warns and keeps running 12.7.0:

    [WARN] Cannot use the pnpm version this project pins: ERR_PNPM_NO_MATURE_MATCHING_VERSION: adding a new package: 15 versions do not meet the minimumReleaseAge constraint: ... Run the install interactively to approve these picks, add them to minimumReleaseAgeExclude in pnpm-workspace.yaml, or wait for the packages to mature.
    12.7.0

Describe the Bug

When the pin is a range, package_manager_to_sync (pnpm/crates/cli/src/cli_args/package_manager.rs) records the running pnpm's version in packageManagerDependencies whenever it satisfies the range:

rust
// A range pin names no exact version, so the running pnpm's version is
// the one the project actually uses.
version_satisfies(PNPM_VERSION, wanted_version)
    .then(|| PackageManagerToSync { ... version: PNPM_VERSION.to_string() })

This runs on every command. Because is_package_manager_resolved compares against the running version, pnpm also overwrites a locked version that already satisfies the range. In our repo, a mature 12.7.0 entry was replaced with 12.8.1 this way. Nothing checks the running version against the project's minimumReleaseAge.

It's fine that the global pnpm was installed without the project's cutoff. The problem is that the project then adopts that version into its lockfile unchecked. The switch to the locked version does apply the project's release-age settings; #16323 keeps them deliberately. So one contributor with a newer global pnpm writes a version into the lockfile that nobody else can install until the cutoff passes. Reverting the lockfile only helps until that contributor runs their next command.

[!IMPORTANT] Updating the global pnpm to the latest release makes the error go away, but it doesn't fix anything. The latest global pnpm is the same version the lockfile records, so pnpm never has to switch or download a pinned pnpm, and the minimumReleaseAge check never runs. That is why the contributor who wrote the lockfile never sees the problem. It only shows up for people and CI jobs running a different pnpm version.

Related: #15396, #16323, #10699

Expected Behavior

The version pnpm writes to packageManagerDependencies should follow the same minimumReleaseAge rules as the switch that installs it. When the running pnpm is younger than the cutoff, pnpm could keep the locked version if it still satisfies the range. Otherwise it could resolve the newest mature version in the range. At minimum, it should warn or prompt the way a regular install does for an immature dependency, instead of recording the version silently.

Which Node.js version are you using?

26.10.0

Which operating systems have you used?

  • macOS
  • Windows
  • Linux

If your OS is a Linux based, which distribution are you using?

No response