Troubleshooting · 鉴权

401 Unauthorized — 多半不是你刚换掉的那把 Key

30 秒版
  1. 确认端点要的是哪个头:ANTHROPIC_AUTH_TOKENAuthorization: BearerANTHROPIC_API_KEYx-api-key——设错了 Key 是好的也会 401。
  2. env | grep -i anthropic 看有没有旧值盖住新值,然后重启客户端(只在启动时读一次)。
  3. 用 curl 发同样请求:curl 通了但客户端 401 = 客户端没读到你以为的变量;curl 也 401 = 凭证或端点的问题。

客户端连到兼容端点时,中间有两层各自独立的认证,401 可能来自其中任何一层,而两者的报错文本一模一样。重新生成自己的 Key 只处理得到其中一层——而且实际上那是比较少见的那一层。

你看到的报错

以下任意一种
API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"invalid x-api-key"}}

401 Unauthorized

Could not resolve authentication method. Expected either apiKey or authToken to be set.

{"error":{"message":"Invalid bearer token","type":"authentication_error"}}

四种都只表示「请求送到了,但服务器不接受它带的凭证」。没有一种会告诉你是哪一层拒绝的——但措辞可以缩小范围。

信息它告诉你的事最可能的原因
invalid x-api-key服务器读到了 x-api-key 头并拒绝了它的值Key 不对——或者端点要的是 Bearer token
Invalid bearer token服务器读到了 Authorization: Bearer 并拒绝了它的值Token 不对——或者端点要的是 x-api-key
Could not resolve authentication method客户端在发出任何东西之前就放弃了两个变量都没设,或不是这个客户端读的那个
只有 401,没有内容有东西拒绝了它,而且没有解释你不知道它在路径上的某个代理或网关

两层认证

谁对谁认证失败时的表现谁能修
第一层你的客户端 → 端点第一次请求就失败,每次都失败
第二层端点 → 它的上游供应商常是间歇性的,或在完全没改配置时突然开始端点运营方

多数排错文章只写得到第一层——「检查你的 Key」。这建议没错,但它解释不了真正让人困惑的那种情况:一小时前还好好的,而你什么都没动。出现这种情况时,问题不在第一层。

按这个顺序排查

1 · 凭证真的进到请求里了吗#

复制粘贴会夹带看不见的东西——结尾换行、不换行空格、从聊天窗口带出来的弯引号。

终端
printf '%s' "$ANTHROPIC_AUTH_TOKEN" | wc -c
printf '%s' "$ANTHROPIC_AUTH_TOKEN" | tail -c 20 | xxd | tail -2

字节数比看得见的长度多一,就是结尾跟着个换行一起被复制进来了。

2 · 你设的变量,产生的是端点要的那个头吗#

这是四种里最安静的一种失败,因为报错信息完全不会提示你

变量客户端发出的请求头
ANTHROPIC_API_KEYx-api-key: <值>
ANTHROPIC_AUTH_TOKENAuthorization: Bearer <值>

如果端点是靠 Authorization: Bearer 认证,而你设的是 ANTHROPIC_API_KEY,请求送达时根本没有 Authorization。服务器回 401,信息说 Key 无效。Key 是好的,错的是头。反过来也会发生。

接 9Coding 时设 ANTHROPIC_AUTH_TOKEN,Key 以 sk-9c- 开头。

3 · 你的 base URL 结尾,是客户端预期的位置吗#

客户端会自己在你给的 base URL 后面接上路径(/v1/messages/v1/chat/completions)。如果你配的 base URL 结尾已经带了 /v1,请求就会打到 /v1/v1/messages。这通常回 404——但先认证再路由的网关会回 401

终端
echo "$ANTHROPIC_BASE_URL"

正确的值就是 https://api.9coding.com——结尾不要斜杠,不要带 /v1

4 · 有没有旧值盖住了你刚设的#

写在 shell 配置文件里的值、写在项目配置文件里的值、以及当前这个 shell 里的值,是三件不同的事。客户端读的是其中一个,你改的可能是另一个。

终端
env | grep -i anthropic

每一条都要看,不要只看你记得设过的那条。然后重启客户端——Claude Code 只在启动时读一次环境变量,长时间运行的进程会沿用它启动时的环境。

5 · 把客户端排除在外#

终端
curl -s -w '\n%{http_code}\n' https://api.9coding.com/v1/models \
  -H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN"
  • curl 回 200、客户端回 401 → 客户端读的不是你以为的那个变量,回到第 4 步。
  • curl 也回 401 → 问题在凭证或端点,不在客户端。
  • curl 连状态码都拿不到 → 这不是认证问题,看连接错误

什么时候这不是你的问题

以下四点同时成立,就是第二层的事,你这台机器上没有东西要修:

  • 今天早些时候还能用,
  • 你没有改任何配置,
  • 指向同一个端点的其他客户端也是一样的错,
  • 而且过一阵子会自己好。

在你自己的配置上再花一小时之前,先去看运营方的状态页与变更日志。一个既不公开状态页也不公开变更日志的端点,是你没办法排错的端点——这件事本身就值得知道。我们的在状态页

提问题时请带上 request id——9Coding 的报错响应里都有一个,形如 (request id: 2026...)。这个 id 加上时间戳、模型名和完整报错文本,就能把那一次调用查出来。只说「用不了」的反馈没法排查。

401 和 403 不是同一个问题

403 表示请求通过了认证然后被拒绝:账号没有那个模型、那个地区或那个功能的权限。换 Key 保证没用。见 403 Forbidden

相关报错