Permalink to 错误与限流错误与限流

所有接口——/v1/v1beta,以及不需要认证的那几个端点——的错误都用同一个响应体:

json
{
  "error": {
    "message": "invalid api key",
    "type": "authentication_error",
    "code": "invalid_api_key",
    "param": null
  }
}
字段用途
code按它分支。稳定、机器可读、足够具体
typeOpenAI 兼容的分类,给已经在按它 switch 的客户端
message给人看的。已脱敏,但是自由文本,不属于契约
param目前恒为 null,为兼容 OpenAI SDK 而保留

type 的取值范围是 invalid_request_errorauthentication_errorpermission_errornot_found_errorrate_limit_errorinsufficient_quotaupstream_errortimeout_errorserver_error

message 在离开我们之前会被脱敏:上游名称、base URL、上游模型名和凭据都不会出现在里面。上游的 原始文本只留在我们的日志里——这也是为什么提工单时附上 X-Request-Id 比粘贴 message 有用得多。

Permalink to 状态码状态码

状态什么时候
400请求本身有问题——缺字段、枚举值不对、URL 不可用
401没有凭据、Key 未知或被禁用、账号被停用
402额度不够
403OAuth token 缺少这条路由所需的 scope
404路由不存在、模型不存在,或任务不属于你
409幂等键冲突,或在产物就绪前请求了 /content
413请求体或上传文件超过上限
425同一个幂等键的请求仍在准备中,稍后重试
429触发速率限制、并发限制,或在途任务过多
499调用方在我们完成之前断开了
500我们的 bug
502上游失败或返回了不可用的内容
503当前没有可用上游,或我们的数据库短暂不可读
504上游没有在限定时间内应答

注意 402503 的差别:402 需要充值,重试没有意义;而来自 no_available_providerprecheck_failed503 应该退避重试——它表示我们这边暂时服务不了,不是你的请求写错了。

Permalink to 限流限流

两条独立的限制,都是按 Key 计算:

限制默认值触发时
每分钟请求数60429 rate_limitedRetry-After: 60
并发请求数15429 too_many_concurrent_requestsRetry-After: 1

表中是默认值,具体部署可能调高。两者分别用令牌桶和信号量实现——超限直接拒绝,不排队。 OAuth access token 没有对应的 Key 行,因此按账号计算。

第三条限制只针对异步媒体:一个账号最多 64queuedrunning 的任务,跨所有 Key 和会话 合并计算。超过返回 429 media_open_job_capacity,带 Retry-After: 30,见 异步任务

**没有 X-RateLimit-* 响应头。**请读 Retry-After 并退避。

Permalink to 怎么安全地重试怎么安全地重试

  • 429503502504:指数退避加抖动重试;有 Retry-After 就遵守它。
  • 429 外的 4xx:不要重试,重试的结果完全一样。
  • 创建任务:带上 Idempotency-Key。用同一个键重试会拿回原来那个 Job,而不是创建并计费第二个。
  • 对话流式:第一个字节之后失败的流我们无法替你重试,HTTP 状态码会停在 200。请检查每一个 SSE 帧里有没有 error 键,需要的话由你自己重发整个请求。

Permalink to 所有路由通用的错误码所有路由通用的错误码

code状态含义
missing_token401没找到任何凭据
invalid_api_key401这把 Key 不存在
key_disabled / key_expired401Key 不可用
account_disabled401所属账号被停用
insufficient_scope403OAuth token 缺少该模态的 scope
insufficient_credits402余额不足以覆盖这次调用
no_account401凭据解析不到可计费的账号
precheck_failed503额度账本短暂不可读
rate_limited429每分钟请求数超限
too_many_concurrent_requests429并发请求数超限
model_not_found404这把 Key 下该模型不可用于此操作
no_capable_provider404有候选上游,但没有一家实现这个能力
no_available_provider503所有候选上游都在冷却中
request_timeout504
request_canceled499客户端断开
not_found404没有路由匹配该方法与路径
internal_error500我们的 bug——请附上 request id

各端点特有的错误码见对应页面: 图片视频音频ChatGemini异步任务

Permalink to 故障转移以及它对你意味着什么故障转移,以及它对你意味着什么

一个上游失败的请求会在你看到错误之前先在另一个上游重试,所以一个 502 表示所有候选都失败了, 不只是第一个。两条边界:

  • 流式响应在第一个字节上线之后不再故障转移;
  • 客户端错误永不重试,因为重试一个写错的请求只会放大负载。

除了可能增加的延迟之外,这个过程对响应是不可见的。请把 /v1/chat/completions 的客户端超时设宽 一些——某些 HTTP 客户端默认的 10 秒连一次长回复都不够,更别说一次故障转移。

Permalink to 健康检查健康检查

有一个不需要认证的端点,用来判断网关是否还能服务:

bash
curl https://hypit.ai/healthz
json
{
  "status": "ok",
  "version": "v0.4.2",
  "db": "ok",
  "outbox_pending": 0,
  "cleanup_running": true,
  "cleanup_pending": 12,
  "cleanup_oldest_due_age_s": 0
}

值得关心的是 statusdb 两个字段,降级时整体返回 503outbox_*cleanup_* 是运维计数 器,可能随时变化。它适合做负载均衡探针或状态页,不要拿它做每次请求前的预检。