三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

【Bug已解决】OSError: You are trying to access a gated repo. 解决方案

【Bug已解决】OSError: You are trying to access a gated repo. 解决方案

【Bug已解决】OSError: You are trying to access a gated repo. 解决方案

一、现象长什么样

加载一个需要授权的模型(如 Llama-2/3、Gemma、某些医疗/金融垂类模型)时,直接报:

from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")

报错:

OSError: You are trying to access a gated repo. Make sure to have access to it. Your request should be authenticated and have the necessary permissions. ... 401 Client Error. (Request-ID: ...) Repository Not Found or Gated.

或者更隐蔽:在 CI / 服务器上跑得好好的,换到一台新机器立刻报这个错——因为那台机器没登录过 HuggingFace。

也可能:你明明在网页上点了「Accept license」,本地还是报 gated。因为网页授权和本地 CLI 登录是两件事,必须本地也登录拿到 token,token 里才带「已授权该 gated repo」的声明。

最迷惑的是:报错说「Repository Not Found」,让人误以为是 repo 名字拼错或模型下架,其实是「没权限」的意思。

二、背景

HuggingFace Hub 上的「gated repo」是需要主动申请授权的仓库:用户在模型页面点 Accept,作者通过后,该用户才被允许下载。下载时,Hub 要求请求带一个已登录的 token,且这个 token 对应的用户必须在该 repo 的授权名单里。

transformersfrom_pretrained内部调用hf_hub下载文件,默认会从以下位置找 token:

  1. 环境变量HF_TOKEN/HUGGING_FACE_HUB_TOKEN
  2. 缓存的登录态(huggingface-cli login写入的~/.cache/huggingface/token);
  3. 显式传入的token=/use_auth_token=参数。

如果三者都没有,或 token 对应的用户没被授权,Hub 返回 401,transformers 包成上面的OSError: gated repo

常见踩坑:

  • 只在网页点了 Accept,没在本地huggingface-cli login→ 本地无 token → 401。
  • 服务器上用 CI secret 注入HF_TOKEN,但 secret 名字拼错(写成HUGGINGFACE_TOKEN)→ 变量没被读到 → 401。
  • 用了use_auth_token=True但本机从未登录 → 没 token 可拿 → 401。
  • 模型作者后来把 repo 改成 gated,你之前能下现在不能下 → 401。

三、根因

根因一句话:访问 gated repo 时,本地没有有效的、已授权该 repo 的 HuggingFace token(或 token 未被from_pretrained读到),Hub 返回 401,被包装成OSError: gated repo

三点展开:

  1. 未登录/无 token:本地没huggingface-cli login,也没设HF_TOKEN,请求匿名 → 401。
  2. token 未被读取:环境变量名错、参数名错(use_auth_tokenvstoken)、或 token 文件权限问题,导致from_pretrained拿不到 token。
  3. 授权未同步:网页点了 Accept 但用户在 Hub 的授权名单里还没生效,或换了个没授权的账号登录。

不是 repo 不存在,是「授权 token 缺失/未生效」。

四、最小可运行复现

不依赖真实 gated 模型,模拟「无 token 访问 gated repo 触发 OSError」:

import os class FakeHub: GATED = {"meta-llama/Llama-2-7b-hf"} AUTHORIZED_USERS = {"valid-token": "alice"} def get(self, repo, token=None): if repo in self.GATED: if not token: raise OSError("You are trying to access a gated repo. (no token)") if self.AUTHORIZED_USERS.get(token) is None: raise OSError("You are trying to access a gated repo. (401 unauthorized)") return f"weights of {repo}" def resolve_token(explicit=None): # 模拟 from_pretrained 找 token 的优先级 return explicit or os.environ.get("HF_TOKEN") or None hub = FakeHub() repo = "meta-llama/Llama-2-7b-hf" # 场景1:完全没 token tok = resolve_token(None) try: hub.get(repo, tok) except OSError as e: print("场景1(无token):", e) # 场景2:有 token 但未授权 tok = resolve_token("someone-else") try: hub.get(repo, tok) except OSError as e: print("场景2(未授权):", e) # 场景3:有效 token tok = resolve_token("valid-token") print("场景3(有效token):", hub.get(repo, tok))

跑出来:场景1/2 触发 gated OSError,场景3 成功。这就是「无有效 token → 401 → gated OSError」的精确复现。

五、解决方案(第一层:最小直接修复)

最小修复:登录拿到 token,并确保from_pretrained能读到它。三种等价做法:

from transformers import AutoModelForCausalLM # 做法 A:先命令行登录(推荐,一劳永逸) # huggingface-cli login # 然后代码里什么都不用传,自动读缓存 token model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf") # 做法 B:环境变量(CI / 服务器常用) # export HF_TOKEN=hf_xxx # 代码里同样不用传 model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf") # 做法 C:显式传 token(注意参数名是 token,不是 use_auth_token 已废弃) model = AutoModelForCausalLM.from_pretrained( "meta-llama/Llama-2-7b-hf", token="hf_你的token", )

关键检查清单:

  • 先在模型页面点Accept拿到网页授权;
  • 再在本机huggingface-cli login(或设HF_TOKEN);
  • 确认登录的账号就是被授权的那个账号(多账号时容易登错);
  • 若仍 401,跑huggingface-cli whoami确认当前 token 对应的用户,以及该用户是否在 repo 授权名单。

这一步单独就让 gated repo 正常下载。

六、解决方案(第二层:结构性改进)

第一层是「手动登录/传 token」。但在多模型、多环境(本地/CI/容器)里,token 来源分散、容易漏。更稳的做法把「token 如何解析、是否授权、报错如何提示」收敛成单一解析器。

from dataclasses import dataclass, field from typing import Optional import os @dataclass class HfAuthResolver: """HuggingFace token 解析与校验的单一入口。""" # 显式 token(优先级最高) explicit_token: Optional[str] = None # 允许的环境变量名(按优先级) env_keys: list = field(default_factory=lambda: ["HF_TOKEN", "HUGGING_FACE_HUB_TOKEN"]) def resolve(self) -> Optional[str]: if self.explicit_token: return self.explicit_token for k in self.env_keys: v = os.environ.get(k) if v: return v # 回退到 huggingface-cli 登录缓存 try: from huggingface_hub import HfApi return HfApi().token except Exception: return None def diagnose(self, repo: str) -> str: tok = self.resolve() if not tok: return (f"访问 {repo} 失败:未找到 token。请 `huggingface-cli login` " f"或设置 HF_TOKEN。并确认已在模型页 Accept 授权。") # 校验 token 能拿到用户信息(说明已登录且有效) try: from huggingface_hub import whoami user = whoami(token=tok) return f"token 有效,当前用户: {user.get('name')}。若仍 401,请确认该用户已被 {repo} 授权。" except Exception as e: return f"token 无效或网络异常: {e}" # 用法 resolver = HfAuthResolver(explicit_token=os.environ.get("HF_TOKEN")) print(resolver.diagnose("meta-llama/Llama-2-7b-hf")) # 解析出的 token 传给 from_pretrained(..., token=resolver.resolve())

结构收益:

  • 单一解析:token 来源(显式/环境变量/CLI 缓存)按优先级统一解析,不散落。
  • 可诊断diagnose把「无 token / token 无效 / 未授权」区分开,排错不再猜。
  • 可复用:本地、CI、容器都过同一个HfAuthResolver,环境差异被吸收。

七、解决方案(第三层:断言 / CI 守护)

写 pytest 守三条:(1) token 解析优先级正确;(2) 无 token 时给出清晰诊断而非裸 OSError;(3) 显式 token 优先生效。

import os import pytest from your_lib import HfAuthResolver def test_explicit_token_wins(monkeypatch): monkeypatch.setenv("HF_TOKEN", "from_env") r = HfAuthResolver(explicit_token="from_arg") assert r.resolve() == "from_arg" def test_env_token_used_when_no_explicit(monkeypatch): monkeypatch.delenv("HF_TOKEN", raising=False) monkeypatch.setenv("HUGGING_FACE_HUB_TOKEN", "from_alt") r = HfAuthResolver() assert r.resolve() == "from_alt" def test_no_token_diagnosis_clear(monkeypatch): monkeypatch.delenv("HF_TOKEN", raising=False) monkeypatch.delenv("HUGGING_FACE_HUB_TOKEN", raising=False) r = HfAuthResolver() msg = r.diagnose("meta-llama/Llama-2-7b-hf") assert "未找到 token" in msg assert "huggingface-cli login" in msg or "HF_TOKEN" in msg def test_diagnose_mentions_authorization(monkeypatch): monkeypatch.setenv("HF_TOKEN", "fake") r = HfAuthResolver() msg = r.diagnose("some/gated") # 即使是假 token,诊断也应提示「确认授权」方向 assert "授权" in msg or "token" in msg

CI 常驻跑这四条后,任何「token 解析优先级错」「无 token 时裸崩」的回归都会立刻爆红。

八、排查清单

OSError: gated repo时按顺序查:

  1. 先确认是不是 401 类错误(gated),不是「repo 真的 404」——gated 本质是权限问题。
  2. 确认已在模型页面Acceptlicense,且授权的账号就是你本地要登录的账号。
  3. 本机跑huggingface-cli login(或设HF_TOKEN),再huggingface-cli whoami看当前用户。
  4. 确认from_pretrained能读到 token:传token=最稳,或确保环境变量名是HF_TOKEN
  5. use_auth_token=已废弃,别再用,改用token=
  6. CI/容器里,确认 secret 名与代码读取的环境变量名一致(常见坑:HUGGINGFACE_TOKENvsHF_TOKEN)。
  7. 仍 401 时,用HfAuthResolver.diagnose(repo)区分「无 token / token 无效 / 未授权」,对症处理。

九、小结

OSError: You are trying to access a gated repo根子是本地没有有效的、已授权该 repo 的 HuggingFace token,或 token 没被from_pretrained读到,Hub 返回 401 被包成该错。修复三层次:第一层huggingface-cli login(或设HF_TOKEN、或显式token=),并确保登录账号已被网页授权;第二层用HfAuthResolverdataclass 统一解析 token 来源优先级并给出可诊断的错误提示;第三层用 pytest 守「token 解析优先级」「无 token 时清晰诊断」「显式 token 优先」。

工程启示:凡是加载可能 gated 的模型,token 管理要集中、可诊断,别让from_pretrained在缺 token 时裸崩。把「无 token / 无效 / 未授权」三种情况用诊断信息区分开,排错效率能高一个数量级。切记网页 Accept 和本地登录是两道独立门槛,缺一不可。

← 返回列表