Visitar URL original
`pnpm install --frozen-lockfile` still rejects a fresh lockfile when an injected package's peer is optional and satisfied by a sibling importer · Issue #16428 · pnpm/pnpm · GitHub
Skip to content

pnpm install --frozen-lockfile still rejects a fresh lockfile when an injected package's peer is optional and satisfied by a sibling importer #16428

Closed

Description

@runspired

Last pnpm version that worked

12.6.x

pnpm version

12.7.0 12.8.0 and 12.8.1

Code to reproduce the issue

The script below fails on 12.7.0, 12.8.0, and 12.8.1. It is a variant of the repro in #16332: instead of a required peer dependency, lib's peer is declared optional via peerDependenciesMeta, and a different workspace project (app2) is the one that actually depends on both lib (injected) and peer.

Save this as repro.sh:

#!/bin/sh
set -eu
PNPM_VERSION=${1:-12.8.1}
dir=$(mktemp -d) && cd "$dir"
mkdir app app2 lib peer
printf 'packages:\n  - app\n  - app2\n  - lib\n  - peer\n' > pnpm-workspace.yaml
echo "{\"name\":\"root\",\"private\":true,\"packageManager\":\"pnpm@$PNPM_VERSION\"}" > package.json
echo '{"name":"peer","version":"1.0.0"}' > peer/package.json
cat > lib/package.json <<'EOF'
{
  "name": "lib",
  "version": "1.0.0",
  "peerDependencies": { "peer": "^1.0.0" },
  "peerDependenciesMeta": { "peer": { "optional": true } }
}
EOF
echo '{"name":"app","private":true,"dependencies":{"lib":"workspace:*"},"dependenciesMeta":{"lib":{"injected":true}}}' > app/package.json
echo '{"name":"app2","private":true,"dependencies":{"lib":"workspace:*","peer":"workspace:*"},"dependenciesMeta":{"lib":{"injected":true}}}' > app2/package.json

pnpm --version
pnpm install --lockfile-only
pnpm install --no-frozen-lockfile   # succeeds, lockfile unchanged
rm -rf node_modules */node_modules
pnpm install --frozen-lockfile      # fails on 12.7.0, 12.8.0, and 12.8.1

### Expected behavior

`pnpm install --frozen-lockfile` should complete successfully, since the preceding --no-frozen-lockfile install leaves pnpm-lock.yaml unchanged.

### Actual behavior

Error: ERR_PNPM_OUTDATED_LOCKFILE

× installing dependencies
╰─▶ Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up
to date with package.json.

    Failure reason:
    local dependency "lib" at "lib" is outdated

help: Regenerate the lockfile with pnpm install --lockfile-only so that
pnpm-lock.yaml reflects the current package.json, then re-run pnpm install --frozen-lockfile.


### Additional information

This looks related to #16332 (fixed by #16346), but that fix doesn't cover this shape. In our real-world case (a monorepo using injectWorkspacePackages: true), the injected package (@ember-data/store) declares its peer via peerDependenciesMeta (optional), and the peer is provided by sibling importers elsewhere in the workspace — not by the importer that consumes the injected package directly. That combination still trips the freshness check on 12.8.1.

Removing peerDependenciesMeta (making the peer required, as in #16332's original repro) or removing app2's dependency on peer makes the frozen install pass, confirming the interaction between "injected package with an optional peer" and "a sibling importer supplying that peer" is what's still mishandled.

Because CI defaults to frozen installs, this continues to break CI for workspaces that inject a package with optional peer dependencies, even after #16346.

reproduces on at least Mac and Ubuntu

### Node.js version

24.19.0 and 26

### Operating System

Linux

### Contributing a fix

- [ ] I am working on a fix

Activity

  1. tunglambk commented on Sep 30, 2026

    @tunglambk
    Contributor

    I opened #16429 to fix this in pnpm v12. The lockfile freshness check now accepts a sibling-supplied optional peer in an injected package's snapshot, including when the peer is declared only in peerDependenciesMeta. The PR has regression tests for both forms and still rejects a lockfile after the optional flag changes.


    Written by an agent (Codex, GPT-6).

  2. added a commit that references this issue on Sep 30, 2026
    d2cb36c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions