Repository navigation
fix(renovate): stop the pnpm version guard breaking every bot lockfile update - #906
Conversation
…e update Every Renovate PR is red on `renovate/artifacts`, and CI then fails with ERR_PNPM_OUTDATED_LOCKFILE even on PRs that touch no lockfile. The pnpm version was pinned in three places: `packageManager`, its `devEngines.packageManager` guard (both 11.13.0, onFail: error), and `renovate.json`'s `constraints.pnpm: "^11.0.0"`. The third one floats. Once pnpm 11.13.1 shipped on 2026-07-16, Renovate started resolving a newer pnpm than the guard allows, so its `pnpm install` aborted and it never wrote pnpm-lock.yaml. No repo commit caused this — the range drifted past the guard on its own. Last successful bot lockfile write was 2026-07-15. Reproduced on unmodified master: pnpm 11.13.0 installs fine, pnpm 11.25.0 aborts with "This project is configured to use 11.13.0 of pnpm." The uv locks still update on the same PRs, which rules out a network or sandbox problem. Two changes: - Drop `constraints.pnpm` so Renovate reads the version from the `packageManager` field instead of a floating range. - Relax `devEngines.packageManager.onFail` to "warn" so a version skew degrades to a warning instead of breaking every bot PR. CI still runs the pinned version, and pnpm still self-switches locally. Verified three paths: CI (pnpm 11.13.0, --frozen-lockfile) still passes; Renovate (pnpm 11.25.0) now writes the lockfile; and the packageManager vs devEngines desync in #855 now installs and produces a correct lockfile. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…-sdk-js None of the sibling repos carry these; actor-templates had drifted. - `config:base` is a deprecated alias that Renovate already maps to `config:recommended`. Rename it so the config says what it means. - `pinVersions` no longer exists in Renovate and is ignored. Drop it. - Set `internalChecksFilter: "strict"` explicitly. This is already the default, so behaviour does not change — the three sibling repos all state it, and stating it here keeps the intent visible if the default ever moves. Deliberately not copied: `rangeStrategy: "replace"`. The siblings set it, but it changes how every future range update is written, which is a bigger call than this PR should make. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@B4nan can you take a look pls? |
| "name": "pnpm", | ||
| "version": "11.13.0", | ||
| "onFail": "error" | ||
| "onFail": "warn" |
There was a problem hiding this comment.
are you sure this is actually needed? renovate works fine on other repos, they all use onFail: error, e.g. https://github.com/apify/crawlee/blob/master/package.json#L157
not sure if the version here needs to be complete, maybe having ^11.13.0 would work too? then you could keep the onfail error too
There was a problem hiding this comment.
^11.13.0 should work but we get this in every install
[WARN] "packageManager" and "devEngines.packageManager" specify different
versions of pnpm in package.json. "packageManager" will be ignored
I will try claude to find some different solution, probably drop contraint and keep onFail: error will be enough
btw sdk and client use warn also
There was a problem hiding this comment.
btw sdk and client use warn also
that's because they use pnpm 10, which proxies some commands to npm
anyway, i am not entirely sure this was a good move either, maybe we can just drop the devEngines completely until they are properly supported everywhere. it sucks we have multiple places where we specify those things, and iirc devEngines are the newest (and likely the future standard) one.
There was a problem hiding this comment.
if i remove devEngines there will be no check at all but with no constraint defined, it should pick one from packageManager field, this should be what we want (?)
There was a problem hiding this comment.
@B4nan rebased, description updated. WDYT? just drop constraint (same as crawlee, sdk)
Reviewer feedback on #906: relaxing `onFail` to "warn" was a bigger hammer than needed. pnpm's devEngines version check is semver-range aware, so a range fixes the Renovate abort while keeping the guard hard. Verified against a standalone pnpm 11.25.0 (what Renovate resolves) and npm 11.16.0: - `^11.13.0` + onFail "error", pnpm 11.25.0 -> exit 0, lockfile written - exact `11.13.0` + onFail "error", pnpm 11.25.0 -> exit 1 (the bug) - `^11.13.0` + onFail "error", pnpm 11.13.0 (CI) -> exit 0 - npm at the repo root -> exit 1, EBADDEVENGINES The last line is why this shape is preferable to "warn". `onFail` governs the package-manager *name* check as well as the version one, so "warn" also stopped blocking `npm install` at the repo root, which bypasses every pnpm-only setting in pnpm-workspace.yaml: the 1-day minimumReleaseAge supply-chain gate, the allowBuilds postinstall allowlist, and the @puppeteer/browsers override. Keeping "error" restores that block. Cost: pnpm string-compares `packageManager` against `devEngines.packageManager`, so every pnpm command now prints `"packageManager" will be ignored`. Corepack and Renovate still read `packageManager`, so the 11.13.0 pin is still honoured where it counts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…son only Reviewer feedback on #906: relaxing the pnpm guard was not needed. The breakage came from `constraints.pnpm: "^11.0.0"` floating past the pin, so dropping that key is the whole fix. Revert `package.json` to master — `devEngines.packageManager` goes back to an exact 11.13.0 with `onFail: "error"`. Verified with a standalone pnpm 11.25.0 (what Renovate resolves) and npm 11.16.0: - ordinary PR branch, exact pin + onFail "error" -> exit 0. With `constraints` gone Renovate resolves 11.13.0 from `packageManager`, which matches the guard, so the artifacts step stops failing. - npm at the repo root -> exit 1, EBADDEVENGINES. `onFail` governs the package-manager *name* check too, so "warn" would also have stopped blocking `npm install` here, which bypasses every pnpm-only setting in pnpm-workspace.yaml: the 1-day minimumReleaseAge supply-chain gate, the allowBuilds postinstall allowlist and the @puppeteer/browsers override. Keeping "error" preserves that block. - a range (`^11.13.0`) also clears the guard, but pnpm string-compares `packageManager` against `devEngines.packageManager`, so it warns `"packageManager" will be ignored` on every command, and corepack rejects a range outright. Not worth it. One case still breaks by design: a Renovate PR that bumps `packageManager` alone leaves `devEngines` behind and aborts, as #855 does. That is now a single red PR instead of the whole queue, and it is fixed with a sync commit bumping both pins — the same way crawlee handles it (apify/crawlee#4050). Also add `rangeStrategy: "replace"`. Renovate's PinVersionsMigration already rewrote the removed `pinVersions: false` to exactly that, so this is behaviour-preserving; dropping the key without it would have fallen back to the `auto` default and changed how every range update is written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…10753 # Conflicts: # renovate.json
Note
TL;DR — fixes the always-failing
renovate/artifacts — Artifact file update failurejob by deleting one line fromrenovate.json. No change topackage.json; the pnpm guard stays exactly as strict as it is on master.Problem
Every open Renovate PR is red on
renovate/artifacts("Artifact file update failure"), and CI then fails withERR_PNPM_OUTDATED_LOCKFILE— including on PRs that touch no lockfile at all. #855, #846, #797 and #882 are still stuck behind this.Root cause
The pnpm version was pinned in three places, and one of them floated:
package.json→packageManagerpnpm@11.13.0package.json→devEngines.packageManager11.13.0,onFail: "error"renovate.json→constraints.pnpm^11.0.0← floatsRenovate resolved its pnpm from the floating range. Once pnpm 11.13.1 shipped on 2026-07-16, that range started resolving above the guard, so Renovate's
pnpm installaborted and it never wrotepnpm-lock.yaml. No repo commit caused this — the range drifted on its own, which is whygit logshows nothing. Last successful bot lockfile write: 2026-07-15 (#785, at pnpm 11.13.0).Reproduced on unmodified master:
^11.0.0resolves to today) →[ERROR] This project is configured to use 11.13.0 of pnpm. Your current pnpm is v11.25.0The uv locks still update correctly on the same PRs, which rules out a network or sandbox problem in Renovate's environment.
Changes
renovate.jsononly.package.jsonis byte-identical to master.constraints.pnpm. This is the fix. Renovate now reads the version from thepackageManagerfield, resolves exactly11.13.0, and matches the guard.config:base→config:recommended. Deprecated alias that Renovate already maps to the new name. No behaviour change.pinVersions: false→rangeStrategy: "replace". Renovate'sPinVersionsMigrationalready rewrote the old key to exactly this, so behaviour is unchanged — but dropping it without the replacement would have fallen back to theautodefault and changed how every range update is written.internalChecksFilter: "strict"explicitly. Already the default, so no behaviour change; the three sibling repos all state it, and stating it here keeps the intent visible if the default ever moves.The last three align this config with
apify/crawlee,apify/apify-client-jsandapify/apify-sdk-js, none of which declareconstraints.What this deliberately does not do
An earlier revision relaxed
devEngines.packageManager.onFailto"warn". That is reverted — the guard is untouched. Two reasons:constraintsrange was the whole cause.onFailalso governs the package-manager name check, so"warn"stops blockingnpm installat the repo root. That bypasses every pnpm-only setting inpnpm-workspace.yaml: the 1-dayminimumReleaseAgesupply-chain gate, theallowBuildspostinstall allowlist, and the@puppeteer/browsersoverride.A range (
^11.13.0) withonFail: "error"also clears the guard, but pnpm string-comparespackageManageragainstdevEngines.packageManager, so it warns"packageManager" will be ignoredon every command, and corepack rejects a range outright.Verification
Against a standalone pnpm 11.25.0 (what Renovate resolves) and npm 11.16.0:
onFail: "error"constraintsstill presentpnpm install --frozen-lockfilenpm installat the repo rootEBADDEVENGINES— guard intactrenovate-config-validatorvalidates the new config.Known remaining case
A Renovate PR that bumps
packageManageralone leavesdevEnginesbehind and still aborts — #855 does exactly this. That is now one red PR instead of the whole queue, and it is fixed by a commit syncing both pins.apify/crawleehandles it the same way (apify/crawlee#4050).After merge
The queued Renovate PRs need a rebase to pick up a valid lockfile. Expect #855, #846, #797 and #882 to go green on their next run.
Separate follow-ups (not in this PR)
pnpm@11.13.0is deprecated upstream as a broken release ("Please install pnpm v11.13.1 or newer"); its@pnpm/exebuild ships without a working binary. Nothing breaks today becausedevEnginesonly compares version numbers and never downloads. Bumping the pin is a prerequisite for droppingdevEnginesentirely, which is the right long-term shape — withoutdevEnginesthere is noonFail, so pnpm defaults todownload, tries to install the broken 11.13.0, and hard-errors on every install.apify/apify-clicarries the same bug:constraints.pnpm: "^11.0.0"pluspackageManager: pnpm@11.11.0againstdevEngines11.8.0. It survives only because itsonFailis"warn", which hides the desync.renovate.jsonenvblock). That diagnosis does not hold: Renovate's pnpm step runs--lockfile-only, which executes no postinstall scripts, and repo-levelenvrequires the self-hostedallowedEnvallowlist (default[]), which the Mend-hosted app does not grant.automerge: truewithautomergeType: "branch", but the org ruleset requires 1 approving review on master — so branch automerge can never fire and the queue piles up. Worth switching toautomergeType: "pr"with GitHub native auto-merge.🤖 Generated with Claude Code