Is there an existing issue for this?
Related issues include #8767 and #8726, but both are closed. In #8767, a recurrence after the previous fix was reported and a contributor requested a new issue with a minimal reproduction. This reproduction also appears related to the fix in #9083.
This issue exists in the latest npm version
Reproduced with npm 12.0.2.
This is not just a request to bump a dependency for a CVE
Current Behavior
When a package declares an optional dependency that is unavailable from the registry, npm 12.0.2 completes a normal npm install and generates package-lock.json. An immediate npm ci using the same npm version rejects that unmodified lockfile as out of sync.
The minimal reproduction uses mdream@1.5.12, which declares the unpublished @mdream/rust-wasm32-wasi@1.5.12 package in optionalDependencies.
npm error code EUSAGE
npm error `npm ci` can only install packages when your package.json and package-lock.json are in sync.
npm error Missing: @mdream/rust-wasm32-wasi@ from lock file
The result differs by npm version:
| npm version |
npm install |
Subsequent npm ci |
WASI placeholder in lockfile |
| 11.13.0 |
succeeds |
succeeds |
generated |
| 11.16.0 |
succeeds |
fails with EUSAGE |
not generated |
| 12.0.2 |
succeeds |
fails with EUSAGE |
not generated |
npm 11.13.0 adds this inert placeholder entry and accepts the lockfile:
"node_modules/mdream/node_modules/@mdream/rust-wasm32-wasi": {
"optional": true
}
npm 11.16.0 and 12.0.2 do not add the placeholder and then report that dependency as missing during npm ci.
Adding --omit=optional to npm ci does not avoid the error because lockfile validation happens first.
Expected Behavior
npm ci should accept an unmodified package-lock.json generated moments earlier by npm install with the same npm version and configuration.
An unavailable optional dependency should either be represented consistently in the generated lockfile or ignored consistently during npm ci validation.
This appears to be a regression of the optional-dependency handling addressed by #9083 (fix(ci): don't error on optional deps in the lockfile).
Steps To Reproduce
Minimal reproduction repository:
https://github.com/kotering/mdream-npm-ci-reproduction
-
Clone the repository into a fresh directory.
-
Run a normal install using the latest npm:
npx --yes npm@12.0.2 install --ignore-scripts --no-audit --no-fund
-
Without modifying package.json or the generated package-lock.json, run:
npx --yes npm@12.0.2 ci --dry-run --ignore-scripts --no-audit --no-fund
-
Observe EUSAGE and Missing: @mdream/rust-wasm32-wasi@ from lock file.
-
The same sequence fails with npm 11.16.0. In a separate fresh checkout, the same sequence succeeds with npm 11.13.0.
Environment
- npm: 12.0.2; also reproduced with 11.16.0
- Node.js: 24.18.0
- OS Name: macOS 26.5.2
- System Model Name: Apple Silicon (arm64)
- npm registry:
https://registry.npmjs.org/
Is there an existing issue for this?
Related issues include #8767 and #8726, but both are closed. In #8767, a recurrence after the previous fix was reported and a contributor requested a new issue with a minimal reproduction. This reproduction also appears related to the fix in #9083.
This issue exists in the latest npm version
Reproduced with npm 12.0.2.
This is not just a request to bump a dependency for a CVE
Current Behavior
When a package declares an optional dependency that is unavailable from the registry, npm 12.0.2 completes a normal
npm installand generatespackage-lock.json. An immediatenpm ciusing the same npm version rejects that unmodified lockfile as out of sync.The minimal reproduction uses
mdream@1.5.12, which declares the unpublished@mdream/rust-wasm32-wasi@1.5.12package inoptionalDependencies.The result differs by npm version:
npm installnpm ciEUSAGEEUSAGEnpm 11.13.0 adds this inert placeholder entry and accepts the lockfile:
npm 11.16.0 and 12.0.2 do not add the placeholder and then report that dependency as missing during
npm ci.Adding
--omit=optionaltonpm cidoes not avoid the error because lockfile validation happens first.Expected Behavior
npm cishould accept an unmodifiedpackage-lock.jsongenerated moments earlier bynpm installwith the same npm version and configuration.An unavailable optional dependency should either be represented consistently in the generated lockfile or ignored consistently during
npm civalidation.This appears to be a regression of the optional-dependency handling addressed by #9083 (
fix(ci): don't error on optional deps in the lockfile).Steps To Reproduce
Minimal reproduction repository:
https://github.com/kotering/mdream-npm-ci-reproduction
Clone the repository into a fresh directory.
Run a normal install using the latest npm:
Without modifying
package.jsonor the generatedpackage-lock.json, run:Observe
EUSAGEandMissing: @mdream/rust-wasm32-wasi@ from lock file.The same sequence fails with npm 11.16.0. In a separate fresh checkout, the same sequence succeeds with npm 11.13.0.
Environment
https://registry.npmjs.org/