
Fix pnpm “Cannot Use 'in' Operator” in GitHub Actions
Fix pnpm's integrity undefined crash in GitHub Actions by replacing broken 11.12.0, pinning one version, and updating the setup step safely.
The short fix
If GitHub Actions fails before install with Cannot use 'in' operator to search for 'integrity' in undefined, check the pnpm version before changing dependencies. pnpm 11.12.0 triggered this crash while its setup process read pnpm's own environment lockfile. It is not evidence that your repository's pnpm-lock.yaml is corrupt.
Move the workflow off 11.12.0. As of August 4, 2026, the npm registry lists pnpm 11.20.0 as the current stable release. Pin that exact version, rerun the job, and review the normal project lockfile only if the install step later changes it.
{
"packageManager": "pnpm@11.20.0"
}The pnpm core issue identifies 11.12.0 and the failing global environment-lockfile path. A separate pnpm/action-setup report reproduces the same error on a GitHub runner while switching from pnpm 11.7.0 to 11.12.0. These are two independent reports of the same failure.
Recognize this failure before changing your app
The useful clues appear before your package install starts:
- The setup step says it is switching or self-installing pnpm.
- The selected version is pnpm 11.12.0, often from packageManager, devEngines.packageManager, or a latest-style action input.
- The stack includes createFullPkgId, lockfileToDepGraph, or installPnpmToGlobalDir.
- The final action message says the self-installer exited with code 1.
If the failure starts inside pnpm install and names a package from your project, this article may not match. Save the first error, the pnpm version, and the workflow step instead of diagnosing from the word integrity alone.
Why deleting the project lockfile is the wrong first move
The pnpm report traces this crash to the package manager's global environment lockfile. Peer-variant snapshots could be read without the matching package metadata, leaving the later integrity lookup with an undefined value. The failing file is part of pnpm's own version-management environment, not the lockfile committed with your application.
Do not delete the repository's pnpm-lock.yaml to repair this setup error. That would rewrite application dependency resolution while leaving the real version-selection problem untouched.
For a local machine already stuck on the broken release, the core issue lists platform-specific locations for the global environment lockfile and says removing that file lets self-update continue. Back it up before removal and verify the exact path on your machine. A GitHub-hosted runner is disposable, so changing the committed pnpm pin and starting a new job is usually cleaner.
Pin one known-good version for local work and CI
Put the exact pnpm version in package.json so the repository, developers, and setup action share one source of truth. Avoid latest in a release workflow. A new package-manager release should arrive as a reviewed dependency change, not as an unannounced change between two identical commits.
{
"name": "web-app",
"private": true,
"packageManager": "pnpm@11.20.0",
"scripts": {
"check": "pnpm lint && pnpm test && pnpm build"
}
}The JSON above is a minimal example and was syntax-checked. Keep the scripts and fields your project already owns. If the repository uses devEngines.packageManager instead, update that existing declaration rather than adding a second conflicting pin.
The merged pnpm guard tested 11.11.0 and 11.13.1 as working targets, while refusing known-broken releases. It also calls out 11.13.0 as unsafe for @pnpm/exe even though the JavaScript wrapper could run. That is why this guide does not recommend moving from 11.12.0 to 11.13.0. See pnpm pull request #13082 for the test matrix and refusal behavior.
Update the GitHub Actions setup step
The current pnpm/action-setup README says pnpm 11 and newer should use the successor action, pnpm/setup. It installs pnpm as a standalone executable and can install the JavaScript runtime in the same step.
This workflow follows the documented input names. It is illustrative because your Node version, caching policy, and install command belong to your project:
steps:
- uses: actions/checkout@v6
- uses: pnpm/setup@v1
with:
runtime: node@24
cache: true
install: false
- run: pnpm install --frozen-lockfile
- run: pnpm run checkThe action can read pnpm 11 from packageManager, so the workflow does not need a second version value. install: false keeps the explicit frozen install step; without it, pnpm/setup installs automatically when it finds a package manifest.
If you must stay on pnpm/action-setup@v6 for a short migration window, omit its version input and let the action read the exact packageManager value. Do not keep version: latest next to an exact repository pin because the action input takes precedence.
Recover a local pnpm that cannot update itself
A local recovery should preserve evidence and avoid broad deletion:
- Record pnpm --version and the full error.
- Inspect packageManager and devEngines.packageManager in the nearest package.json.
- Replace a known-broken pin with a reviewed current version.
- Try pnpm self-update latest if the installed binary can still run that command.
- If self-update still hits the same environment-lockfile error, back up only the global pnpm lockfile at the platform path documented in the issue, then retry.
- Run pnpm --version again, followed by the project's frozen install and normal checks.
pnpm's self-update documentation describes the update command. Its installation guide lists supported installation paths if the current binary cannot recover itself. Use the method your team already manages instead of layering multiple global installations.
Check the fix without hiding another failure
A green setup step is only the first checkpoint. Verify the workflow in order:
- The setup log reports the exact pnpm version you pinned.
- pnpm install --frozen-lockfile succeeds without rewriting the project lockfile.
- The cache key uses the intended pnpm-lock.yaml.
- Lint, tests, and the production build run after setup.
- A fresh pull request runner produces the same result.
Do not add --force, remove the frozen-lockfile check, or commit a regenerated lockfile just to get past a package-manager bootstrap crash. Those changes widen the dependency diff without addressing the broken pnpm release.
Keep the pin reviewable
An exact package-manager pin is useful only if someone updates it deliberately. Let Renovate or Dependabot propose pnpm changes, keep setup and install in separate log sections, and test the package-manager update on a fresh runner before merging.
If the upgrade also moves an older pnpm 11 project configuration, review loke.dev's pnpm 11 configuration migration guide. The self-installer crash and the workspace-configuration move are separate problems, so solve them in separate diffs.
Sources
Primary technical sources: pnpm issue #12959; pnpm/action-setup issue #276; pnpm pull request #13082; the current pnpm setup-action README; pnpm self-update docs; and the pnpm installation guide.