Skip to content
Latchkey

npm "404 Not Found" for a Private Package - Fix in CI

A 404 for a package you know exists usually means npm asked the wrong registry - or asked anonymously, so a private package looks like it does not exist at all.

What this error means

npm install/npm ci fails with 404 Not Found - GET for a scoped/private package, while public packages resolve fine. The package is real; npm is just looking in the wrong place or without credentials.

npm output
npm error code E404
npm error 404 Not Found - GET https://registry.npmjs.org/@acme%2finternal-lib
npm error 404 '@acme/internal-lib@^1.2.0' is not in this registry.

Diagnose it: which registry, and with what credentials?

Registry errors are resolved in a precedence chain, and the effective value is rarely the one in the file you are looking at. Scoped registries, .npmrc files at several levels, and environment variables all combine before a request is made.

Terminal
# the effective, fully merged configuration
npm config list -l | grep -E "registry|_auth|always-auth"

# where each value came from
npm config get registry
npm config get @yourscope:registry

# prove the token works, independently of the install
curl -sI -H "Authorization: Bearer $NPM_TOKEN" \
  "$(npm config get registry)@yourscope%2fpackage" | head -1

Common causes

Scope not pointed at the private registry

Without @acme:registry=https://your-registry/, npm queries the public registry for the scoped package and gets a legitimate 404.

Anonymous request to a private registry

Some private registries return 404 (not 401) for unauthenticated reads to avoid leaking existence. No token means the package is invisible.

Typo in the package name or version

A wrong scope, name, or a version that was never published also produces a genuine 404.

How to fix it

Map the scope and authenticate

Point the scope at the right registry and supply a token.

Terminal
cat > .npmrc <<'EOF'
@acme:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}
EOF
NODE_AUTH_TOKEN="$REGISTRY_TOKEN" npm ci

Confirm the package exists as named

  1. Double-check the scope, name, and version against the registry.
  2. Verify the version in the lockfile was actually published.
  3. If it 404s only in CI, suspect missing scope mapping or token, not a missing package.

How to prevent it

  • Always map private scopes to their registry in .npmrc.
  • Provide CI tokens for private reads.
  • Pin published versions in the lockfile.

Frequently asked questions

What causes npm "404 not Found" for a private package?
There are 3 common causes: scope not pointed at the private registry, anonymous request to a private registry, and typo in the package name or version. Without @acme:registry=https://your-registry/, npm queries the public registry for the scoped package and gets a legitimate 404.
How do I fix npm "404 not Found" for a private package?
There are 2 fixes depending on which cause you have: map the scope and authenticate and confirm the package exists as named. Work through them in order, since the first is the most common.
What does npm "404 not Found" for a private package actually mean?
npm install/npm ci fails with 404 Not Found - GET for a scoped/private package, while public packages resolve fine.
How do I stop npm "404 not Found" for a private package happening again?
Always map private scopes to their registry in .npmrc. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

This is a registry failure, not a bug in your code. Latchkey detects, repairs, and retries it for you. Start free → 30-day trial · No credit card