Is there an existing issue for this?
This issue exists in the latest npm version
Current Behavior
When using a registry other than registry.npmjs.org (e.g., Azure DevOps Artifacts with an upstream source to npmjs), npm install in npm 11 writes platform-specific optional dependency entries to package-lock.json without the version field.
These entries look like:
"node_modules/esbuild/node_modules/@esbuild/android-arm": {
"dev": true,
"optional": true
}
Instead of the expected:
"node_modules/@esbuild/android-arm": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz",
"integrity": "sha512-...",
"cpu": ["arm"],
"dev": true,
"optional": true,
"os": ["android"]
}
This causes:
npm ci or npm install to fail on CI/CD with npm error Invalid Version: on some platforms (notably Windows)
- The broken entries are never repaired by subsequent
npm install, npm install --force, or npm install --package-lock-only — only a full rm -rf package-lock.json && npm install fixes it
- Once the broken lockfile is committed to the repository, all team members and CI pipelines are affected
Expected Behavior
npm install should write complete lockfile entries for all platform-specific optional dependencies, including version, resolved, integrity, cpu, and os fields — regardless of which registry is used.
npm 10 correctly produces complete entries with the same registry configuration.
Steps To Reproduce
-
Set up an Azure DevOps Artifacts npm feed with an upstream source pointing to npmjs.org (or any registry that proxies npmjs)
-
Create .npmrc pointing to the feed:
registry=https://pkgs.dev.azure.com/<org>/<project>/_packaging/<feed>/npm/registry/
always-auth=true
- Create
package.json:
{
"name": "npm11-lockfile-bug-repro",
"version": "1.0.0",
"private": true,
"type": "module",
"devDependencies": {
"vite": "^7.0.0",
"@vitejs/plugin-react": "^4.0.0",
"vitest": "^4.0.0",
"@vitest/coverage-v8": "^4.0.0"
}
}
- Run clean install with npm 11:
rm -rf node_modules package-lock.json
npx npm@11 install --legacy-peer-deps
- Check lockfile for broken entries:
python3 -c "
import json
with open('package-lock.json') as f:
pkgs = json.load(f).get('packages', {})
broken = [k for k, v in pkgs.items() if v.get('optional') and 'version' not in v and k != '']
print(f'Entries without version: {len(broken)}')
for m in sorted(broken)[:5]:
print(f' {m}: {json.dumps(pkgs[m])}')
"
Result with npm 11 + private registry: 46 entries without version
Result with npm 11 + registry.npmjs.org: 0 entries without version
Result with npm 10 + private registry: 0 entries without version
Additional observations
- The broken entries are always nested under the parent package (e.g.,
node_modules/esbuild/node_modules/@esbuild/* instead of top-level node_modules/@esbuild/*)
- With npmjs.org registry, npm 11 hoists all platform variants to the top level with full metadata
- With a private registry (Azure Artifacts upstream proxy), npm 11 only hoists the current platform variants and writes minimal
{"optional": true} stubs for all others
- npm 10 only writes current-platform entries and omits non-current platforms entirely — both approaches are valid, but npm 11's approach of writing entries without version is invalid
- The
--legacy-peer-deps flag does not affect the behavior
- Affected packages:
@esbuild/*, @rollup/rollup-*, @parcel/watcher-* — any package using platform-specific optional dependencies
Related issues
This appears to be a separate/remaining issue not covered by either fix.
Environment
npm: 11.14.1
Node.js: v22.22.0
OS: macOS (also reproduced on Windows CI agents)
Is there an existing issue for this?
This issue exists in the latest npm version
Current Behavior
When using a registry other than
registry.npmjs.org(e.g., Azure DevOps Artifacts with an upstream source to npmjs),npm installin npm 11 writes platform-specific optional dependency entries topackage-lock.jsonwithout theversionfield.These entries look like:
Instead of the expected:
This causes:
npm ciornpm installto fail on CI/CD withnpm error Invalid Version:on some platforms (notably Windows)npm install,npm install --force, ornpm install --package-lock-only— only a fullrm -rf package-lock.json && npm installfixes itExpected Behavior
npm installshould write complete lockfile entries for all platform-specific optional dependencies, includingversion,resolved,integrity,cpu, andosfields — regardless of which registry is used.npm 10 correctly produces complete entries with the same registry configuration.
Steps To Reproduce
Set up an Azure DevOps Artifacts npm feed with an upstream source pointing to npmjs.org (or any registry that proxies npmjs)
Create
.npmrcpointing to the feed:package.json:{ "name": "npm11-lockfile-bug-repro", "version": "1.0.0", "private": true, "type": "module", "devDependencies": { "vite": "^7.0.0", "@vitejs/plugin-react": "^4.0.0", "vitest": "^4.0.0", "@vitest/coverage-v8": "^4.0.0" } }Result with npm 11 + private registry: 46 entries without
versionResult with npm 11 + registry.npmjs.org: 0 entries without
versionResult with npm 10 + private registry: 0 entries without
versionAdditional observations
node_modules/esbuild/node_modules/@esbuild/*instead of top-levelnode_modules/@esbuild/*){"optional": true}stubs for all others--legacy-peer-depsflag does not affect the behavior@esbuild/*,@rollup/rollup-*,@parcel/watcher-*— any package using platform-specific optional dependenciesRelated issues
peerOptionaldependency resolution inbuildIdealTree#8981 — fixpeerOptionaldependency resolution inbuildIdealTree(fixed in 11.10.1)This appears to be a separate/remaining issue not covered by either fix.
Environment
npm: 11.14.1
Node.js: v22.22.0
OS: macOS (also reproduced on Windows CI agents)