Skip to content
Latchkey

Bun install 401 from a private registry (bunfig.toml token) in CI

Bun reached your private registry but was rejected: 401 means no valid token was sent, 403 means the token authenticated but cannot read the package. The registry is up; the auth in bunfig.toml is the problem.

What this error means

bun install fails with a 401/403 for a scoped package while public packages install fine, usually because the registry token was never injected into CI.

Terminal
bun install
error: GET https://npm.acme.internal/@acme%2fui - 401 Unauthorized
error: Failed to install 1 package

Common causes

The registry token is missing or not injected

bunfig.toml references $NPM_TOKEN but the secret was never exposed to the step, so Bun sends an anonymous request and gets 401.

The token is valid but lacks read scope

A 403 means the token authenticated but is not permitted to read that scope or package on the registry.

How to fix it

Configure the registry and token in bunfig.toml

  1. Store the registry token as a repository or organization secret.
  2. Reference it via an env var in bunfig.toml, not a literal token.
  3. Export the secret into the step env so Bun can read it.
bunfig.toml
[install.scopes]
"@acme" = { url = "https://npm.acme.internal/", token = "$NPM_TOKEN" }

Inject the secret in the workflow

Expose the token to the install step; a persistent 403 means the token needs read scope, not a retry.

.github/workflows/ci.yml
- run: bun install --frozen-lockfile
  env:
    NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

How to prevent it

  • Keep registry tokens in CI secrets, referenced via env in bunfig.toml.
  • Grant least-privilege read scope to the package feed.
  • Never commit a literal token in bunfig.toml.

Related guides

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