API 错误码

本站会返回的每一种失败,2026-09-01 打真实端点逐条测过。8 条里有 5 条的状态码指不到真实原因,其中 2 条还会被官方 SDK 默默重试,然后才轮到你的程序看见。

核实于 2026-09-01

状态码指不到真实原因

看 error.code,不要看状态码

模型名写错返回 503,缺 messages 字段返回 500。这两种都是请求本身的错,重试多少次都不会变——但 openai-python、openai-node 和 Anthropic 各家 SDK 默认都会对 408、409、429 与全部 5xx 重试两次,还带指数退避。于是一个拼写错误变成三次往返、几十秒的等待,最后才报出那个第一次就已经确定的原因。真实原因一直在响应体的 error.code 里,说谎的是状态码。

对照表

状态码

按实际遇到的频率排,不按数值排。

  • HTTP 401空字符串
    实际发生了什么
    密钥不存在、已被撤销,或者压根没带 Authorization 头。
    下一步
    到控制台「API 密钥」页确认这把密钥还在,或者新建一把。有一件事可以先排除:不是少了 "Bearer " 前缀——本站连裸密钥也收,所以这从来不是原因。
    SDK 是否重试
    不会——立刻失败
    打真实端点实测
    probes-errors.mjs: invalid-token / missing-auth
    返回的消息
    Invalid token
  • HTTP 503model_not_found状态码指不到真实原因
    实际发生了什么
    这个模型 ID 不在本站清单里,绝大多数情况是从别家文档抄来的(gpt-4o、claude-sonnet-4-5)。服务没有故障,只是一个不存在的模型没有可用线路。
    下一步
    拿 GET /v1/models 的返回对一下,那是唯一权威的清单。本站的 ID 一律是 厂商/型号,例如 deepseek/deepseek-v4-flash。
    SDK 是否重试
    会——默认两次
    打真实端点实测
    probes-errors.mjs: unknown-model
    返回的消息
    No available channel for model gpt-4o under group y-api (distributor)
  • HTTP 403insufficient_user_quota状态码指不到真实原因
    实际发生了什么
    账户余额已经用完。这条消息是中文的,剩余额度还带一个全角 $,所以拿英文关键词去搜什么都搜不到。
    下一步
    到 https://y-api.bestvirtualgoods.com/app/billing 充值。额度立刻恢复,原有密钥继续可用,代码不用改。
    SDK 是否重试
    不会——立刻失败
    上游源码核实,未在本站触发
    service/billing_session.go:355-359
    返回的消息
    用户额度不足, 剩余额度: $0.00
  • HTTP 403pre_consume_token_quota_failed状态码指不到真实原因
    实际发生了什么
    账户还有钱,但这一把密钥撞到了创建时设的额度上限。消息里同时给出这把密钥的剩余额度和本次请求需要的额度。
    下一步
    到「API 密钥」页把这把密钥的上限调高或去掉,或者换一把没设上限的。给账户充值没用——上限是按密钥算的。
    SDK 是否重试
    不会——立刻失败
    打真实端点实测
    probes-errors.mjs: quota-exhausted
    返回的消息
    token quota is not enough, token remain quota: $0.000002, need quota: $0.000074
  • HTTP 500invalid_request状态码指不到真实原因
    实际发生了什么
    请求体缺了必填字段,最常见的是 messages。这本该是 400 一类的请求错误,却报成了服务端错误。
    下一步
    消息里会原样点出字段名,读它而不是读状态码。改请求体;重试一定还是同一个错。
    SDK 是否重试
    会——默认两次
    打真实端点实测
    probes-errors.mjs: missing-field
    返回的消息
    field messages is required
  • HTTP 400invalid_request_error状态码指不到真实原因
    实际发生了什么
    这个端点本站没有——/v1/embeddings、/v1/completions、/v1/images/generations 都落在这一条。而响应体会说 messages 是必填的,那和真实原因完全无关。
    下一步
    本站提供的是 chat completions 与 Anthropic 的 messages 端点。如果某个框架在背后调了 embeddings,那部分得换一家。
    SDK 是否重试
    不会——立刻失败
    打真实端点实测
    probes-errors.mjs: unsupported-endpoint
    返回的消息
    `messages` is required and must be a non-empty array.
  • HTTP 400空字符串
    实际发生了什么
    请求体不是合法 JSON。上游把自己的 "Invalid request:" 前缀拼了两遍,那只是显示问题。
    下一步
    通常是手写的请求体或 shell 引号出了问题。发之前先校验一遍 JSON;在 shell 里把整个 body 放进单引号。
    SDK 是否重试
    不会——立刻失败
    打真实端点实测
    probes-errors.mjs: malformed-json
    返回的消息
    Invalid request: Invalid request: invalid JSON request body
  • HTTP 404空字符串
    实际发生了什么
    POST /v1/messages/count_tokens 没有实现。Claude Code 和 Anthropic SDK 会用它在发请求前估算上下文占用。
    下一步
    你这边不用改。客户端要么跳过这次估算,要么显示一条警告;对话、流式和工具调用都不受影响。
    SDK 是否重试
    不会——立刻失败
    打真实端点实测
    probes-errors.mjs: count-tokens
    返回的消息
    Invalid URL (POST /v1/messages/count_tokens)

静默失败

比报错更麻烦的:HTTP 200

有三种失败会返回 200、不抛异常、让你的程序照常往下跑。错的是内容或者账单——这也正是它们很难自己发现的原因。

图片收下了,然后被忽略

上游给 5 个模型标了 image_ratio。那个标记是计价系数,不是视觉能力。5 个模型全都接受 data URL 图片、返回 200,然后一本正经地回答一张它们没看见的图——探针发的是纯绿色 PNG,没有一个说对颜色。推荐模型反而是直接返回 400 拒收,两种失败里这种更安全。

来自客户端兼容性矩阵

max_completion_tokens 管得住文本,管不住账单

上限传 12,moonshotai/kimi-k2.5 实际计费 261,21.8 倍。截断本身是生效的(finish_reason=length);超出的部分是推理 token,它们计费但不进 content。任何按这个上限估算的成本都会低估同样的倍数。

来自客户端兼容性矩阵

Anthropic 消息 id 没有 msg_ 前缀

POST /v1/messages 返回的是一串裸十六进制 id。凡是断言 msg_ 前缀、或者靠解析 id 来路由响应的代码都会对不上——尽管响应体其余部分是合规的。

来自客户端兼容性矩阵

解析

错误体长什么样

外层永远是 {"error": {...}},但字段集合并不固定:有的错误带 param,有的没有,code 经常是空字符串。解析时把每个字段都当可选的。

401,没有 param 字段
{"error":{"code":"","message":"Invalid token (request id: 2026090114474514374…)","type":"new_api_error"}}
404,有 param 但是空的
{"error":{"message":"Invalid URL (POST /v1/messages/count_tokens)","type":"invalid_request_error","param":"","code":""}}

每条消息尾部都有一个 request id,每次请求都不一样。拿消息和本页对照之前先把它剥掉;反过来,报告问题时请带上它——它是日志里定位你那一次请求的唯一依据。

排查

三步排掉绝大多数问题

按顺序来。每一步排掉一层,答案就在这个序列停下来的地方。

  1. 先确认密钥和线路

    GET /v1/models 不花额度,用的是同一把密钥。返回 200 和一份模型清单,就证明密钥、网络、CDN 边缘三者都没问题——那么问题在请求体里,不在凭证上。

    curl -s https://api.y-api.bestvirtualgoods.com/v1/models -H "Authorization: Bearer $YAPI_KEY" | head -c 200
  2. 用 curl 复现一次

    这一步把 SDK 排除掉。如果 curl 成功而你的代码失败,差别在这个库怎么拼请求,不在本站。

    curl -i https://api.y-api.bestvirtualgoods.com/v1/chat/completions \
      -H "Authorization: Bearer $YAPI_KEY" \
      -H "Content-Type: application/json" \
      -d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"hi"}]}'
  3. 排查期间把重试关掉

    关掉重试之后,由你自己请求引起的 500 或 503 会在第一次尝试就露出来,而不是白等两次。查完记得加回去——面对真正的临时故障,重试是有价值的。

    client = OpenAI(
        base_url="https://api.y-api.bestvirtualgoods.com/v1",
        api_key=os.environ["YAPI_KEY"],
        max_retries=0,  # 仅排查时使用
    )

都不是这几种?

状态页会显示本站自己是否处于劣化状态,含过去 90 天的检测记录。如果那边是绿的而你还卡着,错误体里的 request id 是最值得发给我们的东西。