Skip to content
Latchkey

NuGet private feed "401 Unauthorized" (PAT in nuget.config) in CI

The feed is reachable but rejected the request for credentials. A 401 means no valid personal access token (PAT) was presented; the fix is to inject a token into a feed credential entry, not to change the package reference.

What this error means

dotnet restore fails with "Unable to load the service index" or "Response status code does not indicate success: 401 (Unauthorized)" for a private feed, while nuget.org packages restore fine.

dotnet
error : Unable to load the service index for source https://pkgs.dev.azure.com/org/_packaging/feed/nuget/v3/index.json.
error :   Response status code does not indicate success: 401 (Unauthorized).

Common causes

No credentials configured for the feed

The nuget.config lists the source but has no packageSourceCredentials, so restore sends an anonymous request and is rejected with 401.

An expired or wrong-scope PAT

A token is present but expired, or lacks Packaging read scope, so the feed refuses it.

How to fix it

Add credentials from a CI secret

  1. Store the PAT as a CI secret, never in committed config.
  2. Add a packageSourceCredentials entry that reads the secret via env substitution.
  3. Re-run restore and confirm the 401 clears.
nuget.config
<packageSourceCredentials>
  <contoso>
    <add key="Username" value="ci" />
    <add key="ClearTextPassword" value="%NUGET_PAT%" />
  </contoso>
</packageSourceCredentials>

Inject the token in the workflow

Map the secret into the step env so the config substitution resolves at restore time.

.github/workflows/ci.yml
- run: dotnet restore
  env:
    NUGET_PAT: ${{ secrets.NUGET_PAT }}

How to prevent it

  • Keep feed PATs in CI secrets, never in committed nuget.config.
  • Grant least-privilege Packaging read scope to the token.
  • Rotate tokens on a schedule and update the secret in one place.

Frequently asked questions

What causes ""401 (Unauthorized)" from a private feed"?
The nuget.config lists the source but has no packageSourceCredentials, so restore sends an anonymous request and is rejected with 401.
How do I fix "401 (Unauthorized)" from a private feed?
Add credentials from a CI secret

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card