replacementName silently fails for npm peerDependencies (two distinct failure modes) #44426
Unanswered
straub
asked this question in
Request Help
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
How are you running Renovate?
Mend-hosted app (reproduction), also observed on self-hosted CLI
renovate/renovate:43.252.1in DockerWhich platform are you running Renovate on?
GitHub.com
Which version of Renovate are you using?
43.242.2(Mend-hosted, reproduction) /43.252.1(self-hosted, original observation)Problem description
When a
replacementName/replacementVersionrule targets a package declared inpeerDependencies, Renovate either silently drops the replacement update or leavespackage.jsonunchanged — depending on the version range. Neither case produces a PR.Minimal reproduction repo: https://github.com/straub/renovate-repro-replacement-peerdeps
Raw Renovate log: logs/2026-07-07-renovate-run.log
Bug 1: X-range peer dep (
"*") — replacement update silently droppedrenovate.json:{ "dependencyDashboard": true, "packageRules": [{ "matchDatasources": ["npm"], "matchDepNames": ["istanbul-instrumenter-loader"], "replacementName": "coverage-istanbul-loader", "replacementVersion": "3.0.5" }] }package.json:{ "peerDependencies": { "istanbul-instrumenter-loader": "*" } }Current behavior: No replacement PR, no Dependency Dashboard entry, no warning. The dep appears in
packageFiles with updateswith"updates": []:{ "depType": "peerDependencies", "depName": "istanbul-instrumenter-loader", "currentValue": "*", "updates": [] }Expected behavior: PR renames
istanbul-instrumenter-loader: "*"→coverage-istanbul-loader: ">=3.0.5".Root cause:
determineNewReplacementValue()(lookup/utils.ts) callsversioningApi.getNewValue(). Inversioning/npm/range.ts, the first guard ingetNewValueis:isSemVerXRange("*")istrue, so every strategy exceptupdate-lockfilereturnsnull. ThenullnewValue is then filtered out inlookup/index.ts:The replacement update is dropped entirely —
updateDependencyis never called.Bug 2: Satisfied-range peer dep (
">=x.y.z") —package.jsonunchangedrenovate.json:{ "dependencyDashboard": true, "packageRules": [{ "matchDatasources": ["npm"], "matchDepNames": ["request"], "replacementName": "got", "replacementVersion": "14.0.0" }] }package.json:{ "peerDependencies": { "request": ">=2.0.0" } }Current behavior: Renovate reports
branchName: "renovate/request-replacement", butpackage.jsonis unchanged. The update object has"newValue": ">=2.0.0"— identical tocurrentValue:{ "updateType": "replacement", "newName": "got", "newValue": ">=2.0.0", "branchName": "renovate/request-replacement" }Relevant log lines:
No PR is created.
In the Dependency Dashboard, the update remains under "The following updates are pending. To force the creation of a PR, click on a checkbox below.", but checking that box still does not create a PR.
Expected behavior: PR renames
request: ">=2.0.0"→got: ">=14.0.0".Root cause:
getNewValue({ currentValue: ">=2.0.0", newVersion: "14.0.0", rangeStrategy: "widen" })— sincesatisfiesRange("14.0.0", ">=2.0.0")istrue,widenreturns">=2.0.0"unchanged. SonewValue = ">=2.0.0", identical to the current value.In
manager/npm/update/dependency/index.ts,updateDependency()has an early-return guard:requestis never renamed togotinpackage.json.This same early-return bug affects regular
dependenciestoo when the pinned version equalsreplacementVersion— see discussion #39481 for the identical symptom withframer-motion → motion.Suggested fix
The early return in
updateDependencyshould not fire when the dependency name is changing:For Bug 1,
determineNewReplacementValuewould also need to returncurrentValuerather thannullfor X-ranges when a name change is configured, so the update reachesupdateDependencyin the first place.Beta Was this translation helpful? Give feedback.
All reactions