Skip to content

[BUG] npm 11 writes lockfile entries without version for platform-specific optional deps when using a non-npmjs registry #9342

@ecanturk

Description

@ecanturk

Is there an existing issue for this?

  • I have searched the existing issues

This issue exists in the latest npm version

  • I am using the latest npm

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:

  1. npm ci or npm install to fail on CI/CD with npm error Invalid Version: on some platforms (notably Windows)
  2. 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
  3. 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

  1. Set up an Azure DevOps Artifacts npm feed with an upstream source pointing to npmjs.org (or any registry that proxies npmjs)

  2. Create .npmrc pointing to the feed:

registry=https://pkgs.dev.azure.com/<org>/<project>/_packaging/<feed>/npm/registry/
always-auth=true
  1. 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"
  }
}
  1. Run clean install with npm 11:
rm -rf node_modules package-lock.json
npx npm@11 install --legacy-peer-deps
  1. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bugthing that needs fixingNeeds Triageneeds review for next steps

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions