npm Error Code E404 (tested)

npm error code E404 means the npm registry returned a 404 for the exact package name (and version range) you asked for. Like Docker's 'pull access denied,' npm's message deliberately can't distinguish "this doesn't exist" from "this exists but you don't have access" — both return the same wording.

1. Reproduced: a nonexistent package name

npm install this-package-definitely-does-not-exist-xyz123

npm error code E404
npm error 404 Not Found - GET https://registry.npmjs.org/this-package-definitely-does-not-exist-xyz123 - Not found
npm error 404
npm error 404  The requested resource 'this-package-definitely-does-not-exist-xyz123@*' could not be found or you do not have permission to access it.

The phrase "could not be found or you do not have permission to access it" is the tell — npm is hedging between two different causes with one message, exactly like Docker does for private images.

2. Reproduced: an invalid package name gets a more specific reason

Trying to install a capitalized name produces the same E404, but with an extra line that actually tells you why:

npm install React

npm error code E404
npm error 404 Not Found - GET https://registry.npmjs.org/React - Not found
npm error 404  The requested resource 'React@*' could not be found or you do not have permission to access it.
npm error 404 This package name is not valid, because
npm error 404  1. name can no longer contain capital letters

npm package names have been lowercase-only for years; a capitalized name will never resolve, no matter how you spell it. If you see this specific "name can no longer contain capital letters" line, the fix isn't a typo hunt — it's checking the real, correctly-cased package name on npmjs.com (often not what you'd naively guess, e.g. the npm package for "React" is react, lowercase).

3. Reproduced: a private or scoped package you can't access

npm install @totally-fake-org-xyz/private-pkg

npm error code E404
npm error 404 Not Found - GET https://registry.npmjs.org/@totally-fake-org-xyz%2fprivate-pkg - Not found
npm error 404  The requested resource '@totally-fake-org-xyz/private-pkg@*' could not be found or you do not have permission to access it.

Identical wording to a package that simply doesn't exist. Scoped packages (@org/name) are the most common real-world source of this ambiguity: a private scoped package you're not authenticated for looks exactly like a typo'd public one.

4. How to actually tell the three cases apart

  1. Check the exact name on npmjs.com in a private/incognito window. If the package page loads publicly, it exists and the problem is what you typed (spelling, case, or a wrong scope prefix) — not permissions.
  2. Look for an "invalid name" reason line (like the capital-letters case above) — when present, it's conclusive: the name you typed can never be valid, so stop guessing spellings and go find the real name.
  3. If it's a private/scoped package, check your registry auth:
    npm whoami --registry=https://registry.npmjs.org
    # or, for a private registry:
    cat .npmrc   # confirm the right registry + auth token are configured for that scope
    A real access problem looks identical to a typo until you've confirmed you're authenticated for that specific scope.

5. Common real cause: scope not mapped to the right registry

Outside of typos, the most frequent real-world trigger is a .npmrc that doesn't map a private org's scope to its private registry, so npm tries the public registry (registry.npmjs.org) for a package that only exists on the company's internal one. The fix is a scope-specific registry line, not re-authenticating against the wrong registry:

@yourorg:registry=https://your-private-registry.example.com

Frequently asked questions

Does E404 always mean the package doesn't exist?

No, we confirmed this directly: the identical E404 and wording appeared for a fully nonexistent package name and for a scoped private package that exists but we weren't authenticated for. The message can't distinguish the two cases on its own.

How do I know if the name itself is just invalid?

Check for an explicit reason line like we saw for a capitalized name: 'This package name is not valid, because... name can no longer contain capital letters.' When present, it's conclusive — stop trying spelling variations and look up the real package name instead.

My scoped package install fails with E404 but I know it's private and real — why?

The most common real cause (not a typo) is a .npmrc that doesn't map that scope to the private registry, so npm requests it from the public npmjs.org registry instead, which correctly 404s since the package was never published there.

How do I check if I'm actually authenticated, rather than guessing?

npm whoami --registry=<url> confirms which user (if any) you're authenticated as for a specific registry. An empty or error result there, not the E404 message itself, is the real signal of an auth problem.

Is this the same thing as npm's ERESOLVE error?

No — ERESOLVE is a dependency version conflict between packages that do exist; E404 means the registry couldn't find the requested package/version at all. Different cause, different fix (version/peer-dep resolution vs. name/registry/auth correction).

Written with AI assistance. Measured on 2026-10-03 with npm 11.19.0 / Node 24.21.0, installing real (and deliberately nonexistent) packages against the public npm registry. Every error message below is copy-pasted output, not paraphrased. PlainHeaders is our extension; npm is free.