dotnet restore 401 (Unauthorized) from a private feed in CI
The private feed answered but rejected the request with 401: no credentials were sent, or the token was expired or malformed. The feed is reachable; authentication is the problem.
What this error means
restore fails on the private source with "Response status code does not indicate success: 401 (Unauthorized)" while public nuget.org packages restore fine.
error NU1301: Unable to load the service index for source https://pkgs.dev.azure.com/org/_packaging/feed/nuget/v3/index.json.
Response status code does not indicate success: 401 (Unauthorized).Common causes
No credentials reached the restore step
The feed needs a PAT or token, but the secret was never injected, or nuget.config has no credentials for that source, so restore sends an anonymous request.
The token or PAT expired
A previously working PAT lapsed. Azure Artifacts and GitHub Packages tokens have expiries; once past, every restore returns 401.
How to fix it
Inject a valid PAT via a secret
- Store the feed PAT as a repository or organization secret.
- Add a credentialed source or set the feed username/password from the secret.
- Re-run restore; a valid token turns the 401 into a successful index load.
- run: dotnet nuget add source https://pkgs.dev.azure.com/org/_packaging/feed/nuget/v3/index.json \
--name private --username az --password ${{ secrets.AZ_ARTIFACTS_PAT }} --store-password-in-clear-textRotate an expired PAT
Issue a fresh token with Packaging read scope and update the secret in one place; a 401 from expiry clears once the new token is used.
How to prevent it
- Store feed PATs as CI secrets, never in a committed
nuget.config. - Track PAT expiry and rotate before it lapses.
- Grant least-privilege read scope to the feed for the restore token.