Resolve "Hugging Face 401 Unauthorized"
Quick answer
A Hugging Face 401 Unauthorized means your request was not authenticated — the token is missing, invalid, or expired. Fix it by logging in with huggingface-cli login or setting a valid HF_TOKEN. If you are authenticated but still blocked, the repo is gated or private: accept the model's terms on its Hub page, and make sure your token has access — fine-grained tokens need the gated-repos permission enabled explicitly.
You try to download a model and get:
huggingface_hub.utils._errors.HfHubHTTPError: 401 Client Error: Unauthorized
for url: https://huggingface.co/meta-llama/Llama-3.1-8B/resolve/main/config.jsonOr the more explicit variant:
Cannot access gated repo for url ... Access to model meta-llama/Llama-3.1-8B is
restricted. You must be authenticated to access it.A 401 is specifically an identity failure — the Hub is saying "I don't know who you are." That is different from "I know you but you're not allowed" (a 403) and different again from "that repo doesn't exist for you" (a 404). People burn time trying gated-access fixes on what is actually a bad-token problem, or vice versa.
This guide separates the three cleanly, then walks the fixes: authenticating properly, the two-step dance for gated models, and the fine-grained-token gotcha that trips up almost everyone in 2024 and later.
Quick Answer
A Hugging Face 401 Unauthorized means your request wasn't authenticated —
the token is missing, invalid, or expired. Log in with huggingface-cli login
or set a valid HF_TOKEN. If you're authenticated but still blocked, the repo
is gated or private: accept the model's terms on its Hub page, and make sure
your token has access — fine-grained tokens need the gated-repos permission
enabled explicitly.
TL;DR
- 401 = identity. Missing/invalid/expired token → authenticate.
- Verify with
huggingface-cli whoamibefore guessing. - Gated models need two things: accept terms and a token with access.
- Fine-grained tokens don't access gated repos by default — enable it.
- 401 ≠ 403 ≠ 404. Different meanings, different fixes.
- "Repository Not Found" can mean a private repo you can't see.
- CI/Docker: pass
HF_TOKENas a secret, never commit it.
First, Tell the Three Errors Apart
This is the distinction the error text doesn't make for you:
| Code | Meaning | Typical cause | Fix |
|---|---|---|---|
| 401 Unauthorized | "Who are you?" | No token, or invalid/expired token | Authenticate with a valid token |
| 403 / GatedRepoError | "I know you, but no." | Terms not accepted, or token lacks gated access | Accept terms + fix token scope |
| 404 Repository Not Found | "Can't confirm it exists." | Private repo you can't see, or a typo | Request access / check the id |
Hugging Face deliberately returns "Repository Not Found" for private repos you lack access to, instead of confirming they exist. So a 404 can really be an access problem in disguise — don't assume the repo id is wrong until you've checked your permissions.
The Triage
Answer two questions in order and you'll always land on the right fix:
- Are you authenticated?
huggingface-cli whoami— if it errors, you're not. - If authenticated, is the repo gated or private? Gated needs accepted terms plus token access; private needs org/repo membership.
Step-by-step Solution
Step 1: Verify who you are
Before changing anything, check your current identity:
huggingface-cli whoami- Prints your username → you have a working token; skip to gated/private access.
- Errors or "Not logged in" → you're not authenticated; do Step 2.
Step 2: Authenticate
Pick one method. CLI login is best for a dev machine; the env var is best for CI/servers:
# Interactive login (stores the token in ~/.cache/huggingface/token)
huggingface-cli login
# Or set the environment variable (read automatically by huggingface_hub)
export HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxOr pass the token directly in code:
from transformers import AutoModel
model = AutoModel.from_pretrained(
"your-org/private-model",
token="hf_xxxxxxxxxxxxxxxxxxxx", # explicit token wins over env/cache
)Create the token at huggingface.co/settings/tokens.
A read token is enough for downloading; you only need write to push.
Token resolution order: an explicit token= argument wins, then HF_TOKEN
in the environment, then the cached login file. If a bad HF_TOKEN is set, it
overrides your good huggingface-cli login — which is a very common "I logged in
but still 401" cause. Check with env | grep HF_TOKEN.
Step 3: For gated models, accept the terms
Gated models (Llama, Gemma, Mistral, and many others) require you to accept their license on the Hub before any token works:
- Open the model page, e.g.
huggingface.co/meta-llama/Llama-3.1-8B. - Click Agree and access repository (or Request access if approval is needed).
- Wait for approval if it's manual — instant for most, hours for a few.
Only after this does your authenticated token gain access. Accepting terms without a token, or a token without accepting terms, both fail.
Step 4: Fix fine-grained token permissions
This is the modern gotcha. Fine-grained tokens do not access gated repos by default, even for models you've been granted. In the token's settings:
- Enable "Read access to contents of all public gated repos you can access", or
- Grant the specific repository under the token's permitted resources.
A legacy read token has gated access implicitly; a fine-grained one does not
until you turn it on. If a classic token works and a fine-grained one 403s on the
same model, this is why.
Platform-Specific Notes
CI/CD (GitHub Actions, GitLab)
Store the token as a secret, never in the repo:
# GitHub Actions
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}huggingface_hub reads HF_TOKEN automatically, so no code change is needed.
Never echo the token or commit it — a leaked token is a security incident.
Docker
Pass the token at run time, not build time, so it isn't baked into a layer:
docker run -e HF_TOKEN=hf_xxx your-imageFor builds that must download gated models, use BuildKit secrets
(--mount=type=secret) rather than an ARG or ENV, which persist in the image
history.
Spaces / notebooks
In a Hugging Face Space, add the token as a repository secret named
HF_TOKEN. In Colab/Kaggle, set it via the secrets manager and load it into the
environment — don't paste it into a cell you might share.
Verification Steps
huggingface-cli whoamiprints your username.- A gated download succeeds:
from huggingface_hub import hf_hub_download
p = hf_hub_download("meta-llama/Llama-3.1-8B", "config.json")
print(p) # a local path, no 401- The model page shows "You have been granted access" (gated case).
env | grep HF_TOKENshows the token you expect — not a stale one.- In CI, the job logs show the download succeeding without printing the token.
Green state: whoami names you, the gated download returns a path, the model
page confirms access, and no HF_TOKEN in the environment contradicts your login.
Security Best Practices
- Use
read-scoped or fine-grained tokens for downloads — never awritetoken in a training job. - One token per environment (laptop, CI, prod) so you can revoke one without breaking the others.
- Never commit tokens or print them in logs; rotate immediately if leaked.
- Prefer fine-grained tokens in production — scope them to the exact repos you need.
- Set
HF_TOKENfrom a secret store, not a.envcommitted to the repo.
Prevention
- Authenticate once per environment and verify with
whoami. - Accept gated terms before the first automated run, not during it.
- Enable gated-repo access on fine-grained tokens up front.
- Store
HF_TOKENas a CI/Docker secret, never in code. - Add a startup check that calls
whoamiand fails loudly if unauthenticated. - Document which token each service uses so rotation is painless.
Troubleshooting Matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 on any download | Not authenticated | huggingface-cli login / set HF_TOKEN |
| 401 after login | Stale/overriding HF_TOKEN | env | grep HF_TOKEN; re-login |
| 403 / GatedRepoError | Terms not accepted | Accept on the model page |
| 403 with fine-grained token | Missing gated permission | Enable gated-repos access on the token |
| 404 Repository Not Found | Private repo / typo | Request access / verify the id |
| Works locally, 401 in CI | Secret not set | Add HF_TOKEN secret to the job |
| 401 only in Docker | Token not passed | -e HF_TOKEN=... at run time |
| Access page says "granted" but still 401 | Wrong/expired token | Create a fresh token, re-authenticate |
Related Guides
- Resolve OSError: Can't load tokenizer
- Fix SentenceTransformer model download failed
- Fix "bitsandbytes CUDA Setup failed"
- Fix "Token indices sequence length is longer than the specified maximum"
- Securely managing API keys and tokens in ML pipelines
External References
- Hugging Face — User access tokens
- Hugging Face — Gated models
- huggingface_hub — Authentication
- Hugging Face — Manage your Space secrets
FAQs
Is a 401 ever caused by the model repo, not my token? Rarely. A 401 is about authentication, so it's almost always your token or login. If the token is valid and you've accepted the terms, a persistent failure is more likely a 403 (permissions) or a temporary Hub outage — check the status page.
Do I need a write token to download models?
No. read scope is sufficient for downloading, including gated models you've been
granted. Use write only for uploading. Smaller scope is safer.
Why does token=True sometimes work and token="hf_..." fail?
token=True tells the library to use your cached login, which may be a different
(working) token than the string you pasted. If a literal token fails, it's likely
invalid, expired, or lacks gated access — regenerate it.
Can I check a token without downloading anything?
Yes: huggingface-cli whoami uses the token to identify you. If it prints your
username, the token authenticates; if it errors, the token is the problem.
The model was public yesterday and 401s today — what changed? The maintainer likely gated it, or your token expired/was rotated. Visit the model page: if it now shows a terms prompt, accept it and re-authenticate.
Key takeaways
- •A 401 means 'who are you?' — the token is missing, invalid, or expired, so authenticate first.
- •Verify your identity with huggingface-cli whoami before anything else; it confirms the token actually works.
- •Gated models need two things: accept the terms on the model page AND use a token that has access.
- •Fine-grained tokens do not access gated repos by default — enable the gated-repos permission or grant the specific repo.
- •401, 403/GatedRepoError, and 404 'Repository Not Found' are three different failures with three different fixes.
- •A 'Repository Not Found' can mean a private repo you can't see — Hugging Face hides existence rather than leaking it.
Frequently asked questions
What does Hugging Face 401 Unauthorized mean?
It means your request reached the Hub but was not authenticated. No token was sent, or the token is invalid, expired, or revoked. It is an identity problem, not a permissions one — the fix is to log in with huggingface-cli login or set a valid HF_TOKEN, then retry.
How do I fix a 401 when downloading a gated model like Llama or Gemma?
Two steps are required. First, open the model page on huggingface.co and click Agree/Request access to accept the terms. Second, authenticate with a token that has access — huggingface-cli login or token=hf_... in code. Missing either step returns a 401 or 403.
My token works in the browser but not with a fine-grained token — why?
Fine-grained tokens do not include gated-repo access by default. In the token settings, enable 'Read access to contents of all public gated repos you can access', or grant the specific repository. A classic read token has this implicitly; a fine-grained one does not until you turn it on.
What's the difference between 401, 403, and 404 on Hugging Face?
401 Unauthorized means the token is missing or invalid — authenticate. 403 or GatedRepoError means you are known but not permitted — accept terms or fix the token scope. 404 Repository Not Found often means a private repo you cannot see, or a typo. They need different fixes, so read the code, not just the word 'error'.
How do I set the Hugging Face token in CI or Docker?
Pass it as an environment secret named HF_TOKEN — never bake it into the image or commit it. In GitHub Actions, add it as a repository secret and export it as HF_TOKEN in the job. The huggingface_hub library reads HF_TOKEN automatically, so no code change is needed.
Why do I still get 401 after huggingface-cli login?
Usually a stale or overriding token. An invalid HF_TOKEN in the environment overrides your login, or an old token sits in the cache. Run huggingface-cli whoami to see who you are, then huggingface-cli logout and log in again with a fresh token from your account settings.