Cargo "failed to authenticate" - Private Registry Auth in CI
Cargo tried to fetch a crate from a private registry (or a private git source) and the credentials were missing or rejected. Without a valid token the registry returns 401 and resolution fails.
What this error means
cargo fails with failed to authenticate, 401 Unauthorized, or no token found for registry while updating or downloading from a non-crates.io source. It happens in CI even when it works locally, because the local credential isn’t present on the runner.
error: failed to download from `https://crates.mycompany.com/api/v1/crates/internal/1.0.0/download`
Caused by:
failed to get successful HTTP response from ... 401 UnauthorizedCommon causes
No registry token on the runner
The private registry needs a token that exists in your local ~/.cargo/credentials.toml but was never provided to CI as a secret/env var.
Wrong or expired credentials
The token is present but invalid, expired, or scoped to the wrong registry, so the server rejects it with 401.
How to fix it
Provide the token via an environment variable
Cargo reads a per-registry token from a CARGO_REGISTRIES_<NAME>_TOKEN env var - supply it from a CI secret.
# registry named "my-registry" in .cargo/config.toml
export CARGO_REGISTRIES_MY_REGISTRY_TOKEN="${{ secrets.CARGO_REGISTRY_TOKEN }}"
cargo build --lockedDeclare the registry source
Make sure the registry index is configured so Cargo knows where to authenticate.
# .cargo/config.toml
[registries.my-registry]
index = "sparse+https://crates.mycompany.com/index/"How to prevent it
- Inject registry tokens as CI secrets via
CARGO_REGISTRIES_<NAME>_TOKEN. - Rotate and scope tokens narrowly to the registries that need them.
- Keep
credentials.tomlout of version control.