Back to publishing & release Automate semantic versioning Manage release channels Harden the supply chain

Fixing npm publish E404 Not Found

npm publish failing with E404 is confusing because you are trying to create something, and the registry says it cannot find it. The 404 is rarely about a missing package. The npm registry returns 404 for many authorisation failures on scoped packages, deliberately, so it does not reveal whether a private package or scope exists. The real causes are an unauthenticated request, a scope your account cannot publish to, a request sent to the wrong registry, or a mismatch in a trusted publishing configuration. This guide reads the error, narrows down the cause, and fixes each.

Exact symptoms and error messages

npm notice Publishing to https://registry.npmjs.org/ with tag latest and public access
npm error code E404
npm error 404 Not Found - PUT https://registry.npmjs.org/@acme%2fsdk - Not found
npm error 404
npm error 404  '@acme/sdk@1.4.0' is not in this registry.
npm error 404
npm error 404 Note that you can also install from a
npm error 404 tarball, folder, http url, or git url.

The last lines are generic install advice printed for every 404 — ignore them. The two useful facts are the method and URL (PUT https://registry.npmjs.org/@acme%2fsdk), which tell you which registry and package name the publish targeted.

Variants from other registries look similar:

npm error 404 Not Found - PUT https://npm.pkg.github.com/@acme%2fsdk - The requested resource could not be found.

Root cause analysis

For a PUT to a scoped package name, the npm registry answers 404 when the requester is not allowed to publish there — whether because they are not logged in, the scope belongs to someone else, or the package is private and the requester has no access. Returning 403 would confirm that the scope or package exists; 404 reveals nothing. How registry authentication works is covered in npm Registry Publishing Workflows.

Narrowing down a publish E404 Checks whether the request went to the right registry, whether it was authenticated, whether the account can publish to the scope, and whether trusted publishing claims match. Is the PUT URL the registry you expect? Fix scope routing @acme:registry or publishConfig yes Does npm whoami --registry <url> work? Authenticate token for that exact registry host yes no Can this account publish to @acme? Get org access or create scope npm org ls acme yes no Trusted publishing mismatch repo, workflow file or environment differs no
Work from the URL in the error outwards; most E404s are authentication or scope problems, not missing packages.

The causes, from most to least common:

  1. Not authenticated for that registry. No token, an expired token, or a token configured for a different registry host (for example, //registry.npmjs.org/:_authToken set but the publish goes to npm.pkg.github.com).
  2. No permission on the scope. The @acme scope is an npm organisation your account is not a member of, or a member without publish rights; or @acme is someone else's user scope.
  3. The scope does not exist. Publishing the first @acme/* package requires an npm organisation or user named acme. If neither exists, create the organisation first.
  4. Wrong registry. publishConfig.registry or a scoped registry mapping sends the publish somewhere unexpected — often a private registry that does not host this scope.
  5. Trusted publishing mismatch. The OIDC identity does not match the package's trusted publisher, so the request is effectively unauthenticated.

Resolution

Check where the publish is going:

npm config get registry
npm config get @acme:registry
node -p "require('./package.json').publishConfig"

publishConfig.registry overrides everything for publishing. Make sure it matches where the package should live:

{
  "name": "@acme/sdk",
  "publishConfig": {
    "access": "public",
    "registry": "https://registry.npmjs.org/"
  }
}

Check authentication for that exact registry:

npm whoami --registry https://registry.npmjs.org/
npm whoami --registry https://npm.pkg.github.com/

ENEEDAUTH or a 401 here confirms missing or invalid credentials. In CI, the token must be written for the right host — actions/setup-node with registry-url writes //<host>/:_authToken=${NODE_AUTH_TOKEN} into a project .npmrc, so NODE_AUTH_TOKEN must be set in the publish step's environment.

Check scope permissions:

npm org ls acme                     # are you a member? (org owners/admins can list)
npm access list packages @acme      # which packages can you access?
npm access list collaborators @acme/sdk

If the organisation does not exist, create it on npmjs.com (free organisations can publish public packages). If it exists but you lack rights, an owner must add you to a team with read-write access to the package, as covered in Publishing Scoped Packages to npm.

For trusted publishing, compare the trusted publisher settings on the package with the workflow exactly — owner, repository, workflow filename and environment — as described in Publishing from CI with npm Trusted Publishing.

E404 versus E401 versus E403 on publish Compares what each publish error code usually means and the first thing to check. usual meaning first check E401 credentials missing or invalid npm whoami --registry E403 authenticated but not allowed, or 2FA/policy access, 2FA, version exists E404 (scoped) no permission or unauthenticated, disguised registry URL, whoami, scope access E404 (unscoped) usually auth or registry mismatch registry URL, token host
For scoped packages, npm often reports authorisation failures as 404 to avoid revealing private names.

Token types and their scopes

npm's granular access tokens add another way to hit a 404: a token can be valid, authenticate successfully for npm whoami, and still lack permission for the package you are publishing. Granular tokens are scoped to specific packages, scopes or organisations, with read-only or read-write permission, an expiry date and optional IP ranges. A token created for @acme/ui cannot publish @acme/sdk, and the registry answers that attempt the same way it answers an anonymous one.

Why a valid token can still get a 404 A token may authenticate but lack write permission, be limited to other packages, be expired, or be restricted to other IP ranges. npm whoami works, publish returns 404 inspect the token's settings Needs read-write publish requires write read-only Add this package or its whole scope other packages Renew or allow runner IPs CI IPs change expired / IP
Check the token's package list, permission level, expiry and IP restrictions — not just whether it logs in.

List your tokens with npm token list (or on the npm website under Access Tokens) and check the package and permission columns. For CI, prefer trusted publishing where supported; where a token is unavoidable, create one granular token per repository, limited to the packages that repository publishes, with read-write permission and an expiry that matches your rotation schedule, as described in Rotating npm Publish Tokens Without Breaking CI.

Organisations add one more layer: an organisation can restrict which members and tokens may publish, and packages can require two-factor authentication for publishing. A token that bypasses 2FA must be explicitly allowed by the package's publishing settings; otherwise the registry may respond with 403 or, for some scoped cases, the same opaque 404.

Worked example: publishing to the wrong registry in CI

A team moves @acme/sdk from GitHub Packages to the public npm registry. The first release job fails with 404 Not Found - PUT https://npm.pkg.github.com/@acme%2fsdk. The URL gives it away: the repository's committed .npmrc still contains @acme:registry=https://npm.pkg.github.com, which overrides the default registry for the scope. Adding publishConfig.registry set to the public registry fixes the publish, and the stale scope mapping is removed from .npmrc once consumers have migrated. Routing between registries is covered in Routing Scopes to Multiple Registries in .npmrc.

Monorepo release jobs

In a monorepo, one release job publishes many packages in a row, and E404 often hits only some of them. That pattern is informative. If the failing packages share a scope the others do not use, the token or trusted publisher configuration lacks that scope. If they are new packages being published for the first time, the organisation's default permissions may not grant the release team write access to new packages, or trusted publishing cannot be configured yet because the package does not exist. If they are the packages with a publishConfig.registry override, they are going somewhere else entirely.

Release tools such as Changesets stop at the first failure by default, leaving later packages unpublished and the release half-done. Run a dry-run publish for every package in the release before the real run, and when a partial release does happen, fix the cause and re-run the publish step — tools skip versions that are already on the registry, so re-running is safe.

Debugging with verbose output

npm publish --dry-run --loglevel=verbose 2>&1 | grep -Ei "registry|auth|publishing"
npm publish --loglevel=http 2>&1 | grep -E "PUT|GET" | head

--dry-run shows the resolved registry and access settings without uploading. --loglevel=http prints each request with its status, which confirms whether an authorization header was sent (npm logs that a token is used without printing it).

Prevention and CI/CD guardrails

  • Set publishConfig.registry explicitly in every published package.
  • Run npm whoami --registry <url> as a step before publishing in CI, so authentication failures are reported clearly.
  • Create npm organisations for your scopes before the first publish, and manage access through teams.
  • Dry-run releases when changing registries, as covered in Dry-Running a Publish Before Release.

Frequently Asked Questions

Why does npm say the package is not in the registry when I am publishing it? That message is generic 404 text. For publishes it almost always means the registry refused the request without revealing why — typically authentication or scope permissions.

Can a 404 mean the version already exists? No. Publishing an existing version returns 403 with "cannot publish over the previously published versions", covered in Fixing npm 'Cannot Publish Over Previously Published Version'.

Does unscoped publishing ever return 404? Yes, when authentication is missing or the request goes to a registry that does not accept it. Unscoped name conflicts return 403 instead.

Why does it work from my laptop but not from CI? Your laptop uses credentials from your user ~/.npmrc (from npm login), which CI does not have. CI relies on the token or OIDC configuration in the workflow, which is where the problem is.

Related

npm Registry Publishing Workflows