Skip to content
Latchkey

GitHub Packages npm "401" (GITHUB_TOKEN read:packages scope) in CI

Installing from GitHub Packages npm returned 401. Either the token has no read:packages scope, or .npmrc does not send an _authToken for the npm.pkg.github.com host.

What this error means

npm install fails with "npm error code E401" and "npm error 401 Unauthorized - GET https://npm.pkg.github.com/@scope%2fpkg" while public registry packages install fine.

npm
npm error code E401
npm error 401 Unauthorized - GET https://npm.pkg.github.com/@acme%2fwidgets - authentication token not provided

Common causes

The token lacks read:packages

A classic PAT needs read:packages; the default GITHUB_TOKEN needs packages: read in the job permissions. Without it, reads are unauthorized.

.npmrc does not route the scope with a token

Without a //npm.pkg.github.com/:_authToken= line and a scope registry mapping, npm sends anonymous requests to GitHub Packages.

How to fix it

Grant read:packages and configure .npmrc

  1. Add packages: read to the workflow job permissions (or use a PAT with read:packages).
  2. Map the scope to the registry and set the auth token in .npmrc.
  3. Re-run the install.
.npmrc
@acme:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}

Set job permissions in the workflow

Give the job read access to packages and pass the token as NODE_AUTH_TOKEN.

.github/workflows/ci.yml
permissions:
  contents: read
  packages: read
env:
  NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

How to prevent it

  • Grant packages: read (or a PAT with read:packages) for installs.
  • Keep the scope-to-registry mapping and auth token in .npmrc.
  • Use NODE_AUTH_TOKEN so the token is not hard-coded.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →