Disable pnpm's implicit install-on-run in favor of explicit installs - #5804
Open
lukemelia wants to merge 2 commits into
Open
Disable pnpm's implicit install-on-run in favor of explicit installs#5804lukemelia wants to merge 2 commits into
lukemelia wants to merge 2 commits into
Conversation
…flake pnpm 11 defaults verify-deps-before-run to `install`, so every `pnpm run` / `pnpm exec` first checks node_modules freshness and silently runs a workspace-wide install when the check fails. In CI the check never passes, even immediately after the init action's `pnpm install --frozen-lockfile` (and even after one of these implicit installs completes), so every pnpm invocation in a job pays a redundant 4-16s install. The fatal case is the service boot: `run-p` launches ~9 pnpm scripts at once, each kicking off its own concurrent install into the same node_modules. They stomp each other's bin links (the "Failed to create bin ... ENOENT" warnings visible in green shards) and occasionally deadlock; when start:matrix's install is the one that wedges, the Synapse container is never created and the shard fails with "Failed to reach Synapse ... after 60 attempts (~300s)". This is the mechanism behind the recurring "Synapse startup race" flake, which hit 12 host shards across three PRs today alone. Setting verifyDepsBeforeRun: false restores pnpm 10 behavior: scripts run against node_modules as-is, and installs happen only when explicitly requested. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pnpm 11 reads workspace settings (catalog, overrides, patchedDependencies, allowBuilds, verifyDepsBeforeRun) from pnpm-workspace.yaml, but no workflow path filter included it — a settings-only change that doesn't touch the lockfile ran zero suites. Add it alongside pnpm-lock.yaml in every filter, including ci-host's index-cache invalidation case, since overrides and patches can change indexing behavior the same way a lockfile change can. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lukemelia
force-pushed
the
fix-ci-pnpm-implicit-installs
branch
from
August 18, 2026 21:11
d5e8aba to
3691ab4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
verifyDepsBeforeRun: falseinpnpm-workspace.yaml. pnpm 11 defaults this setting toinstall, which makes everypnpm run/pnpm execcheck node_modules freshness first and silently run a workspace-wide install when the check fails. Withfalse, scripts run against node_modules as-is and installs happen only when explicitly requested — the pnpm 10 behavior this workspace ran on previously.pnpm-workspace.yamlto every workflow path filter that already listspnpm-lock.yaml(and to ci-host's index-cache invalidation case). The file carries dependency-resolution settings (catalog, overrides, patchedDependencies, allowBuilds, verifyDepsBeforeRun), but a settings-only change that doesn't touch the lockfile previously ran zero suites.Why
The freshness check never passes in CI — not even immediately after the init action's
pnpm install --frozen-lockfile, and not after one of the implicit installs itself completes — so every pnpm invocation in a CI job pays a redundant 4–16s install. Green host-shard logs show the sequence plainly: the explicit install finishes, then three more implicit installs run during setup, then several concurrent ones fire whenrun-pboots the test services.That concurrency is the fatal case.
start:matrix,start:smtp,start:host-dist, and the rest are eachpnpm runinvocations, so each spawns its own workspace-wide install into the same node_modules. They stomp each other's bin links (theFailed to create bin … ENOENTwarnings visible even in passing shards) and occasionally wedge each other. Whenstart:matrix's install is the one that hangs,start-matrix.shnever reachespnpm assert-synapse-running, the Synapse container is never created, and the shard fails withFailed to reach Synapse at http://localhost:8008/_matrix/client/versions after 60 attempts (~300s)— the recurring "Synapse startup" flake. Failing-shard logs show that install still running at teardown, killed by SIGTERM five minutes after it started, withError response from daemon: No such container: boxel-synapse-ciin between.The same mechanism slows local dev: every
pnpm <script>pays the check, andpnpm start:allfans out the same concurrent implicit installs.Test plan
pnpm config get verify-deps-before-runreportsfalsewith this change (previously unset, defaulting toinstall).Done in Ns using pnpmimplicit-install output between the init action's install and the test run, and noFailed to create bin … ENOENTwarnings during service boot.🤖 Generated with Claude Code