MonkeyAI 排错 · ChatGPT Plus · OAuth 账号池

ChatGPT Plus 5 小时窗口:OAuth 账号池为什么返回 503

如果你的 OpenAI 兼容中转站返回 HTTP 503,响应体是 {"error":{"message":"Service temporarily unavailable","type":"api_error"}},而中转日志写着 openai_chat_completions.account_select_failed error="no available accounts",问题通常不在你的 key。它来自 ChatGPT Plus OAuth 账号池的滚动 5 小时窗口被单一账号打到零,failover 已经没有可用的替代账号。

1,2057 天内 OpenAI/ChatGPT Plus 账号池上的 503 响应(2026-08-02 — 2026-08-08)
2417 天内 account_id 16 的上游 401 切换事件
约 30-40 / 天每日稳定节拍,不是一次性故障
0大多数失败的 excluded_account_count — 池子空了,不是被限速

滚动 5 小时窗口到底是什么

ChatGPT Plus 账号会被施加一种滚动使用配额,OpenAI 大约按 5 小时的节拍重置。OpenAI 官方错误文档并没有把精确预算写进 API 客户端可见的错误面 — Error codes guide 里没有 504,也没有 "rolling window exhausted" 这一行。从中转侧观察到的是一个滑动配额,当单一 Plus 账号流量持续偏高时,这个配额会被打到零。

窗口按账号计算,不按模型。在同一个 Plus OAuth 登录下切换模型不会重置计时器,也不会给你新的预算。

OpenAI 公开的错误面列了 401 / 403 / 429 / 500 / 503。从中转出来的 504 指向网关,不是模型。在多次上游 401 之后从中转出来的 503 指向中转账号池,也不是上游的配额文档。

为什么客户端拿到的是 503 而不是 429

中转并不会把 OpenAI 的内部配额信号作为 429 直接吐给客户端。我们 2026-08-07 在生产日志中观察到的链路是这样的:

# 中转日志(节选自 journalctl -u sub2api)
WARN  openai_chat_completions.upstream_failover_switching
      upstream_status=401  account_id=16  switch_count=1  max_switches=10
      model=gpt-5.6-sol    stream=true
WARN  openai_chat_completions.account_select_failed
      error="no available accounts"  excluded_account_count=0
INFO  http request completed  status_code=503  latency_ms=16  model=gpt-5.6-sol

逐步拆解:

  1. 中转选出一个 ChatGPT Plus 账号(我们的日志里是 account_id 16),把请求转发过去。
  2. OpenAI Plus 给中转返回 401,意味着这个账号的滚动窗口已经耗尽,它的 token 在推理流量上被视作失效。
  3. 中转把这个账号标记为耗尽,开始 failover — 我们观察到的配置最多切换 10 次。
  4. 池子里其它 Plus 账号状态相同,每次切换都拿到 401。
  5. 切换预算耗尽后,中转向客户端返回 503,JSON 体里写 "no available accounts"。

中转吸收了 OpenAI Plus 的配额信号,然后翻译成自己的 503。客户端永远看不到那个上游 401。

这和客户端直接收到 401 不是一回事

看到什么失败层去哪里查
中转返回 401,响应体提到 token 无效你的 key 或 headerAuthorization header、key 前缀、中转上的账号
中转返回 404路由不匹配Base URL、endpoint 路径、模型 id
429 带结构化响应体并附 Retry-After单账号的配额,上游是健康的降并发,尊重 Retry-After
多次上游 401 之后 503 报 "no available accounts"中转的 Plus OAuth 账号池 — 滚动 5 小时窗口服务端日志:upstream_failover_switching 后接 account_select_failed
中转返回 504反代计时器proxy_read_timeout、路由、上游延迟

动手之前先做一个小验证:用同一个 key 调 /v1/models,应该返回 200 JSON 模型列表。如果这条通了,而 /v1/chat/completions 返回 503,失败就在推理账号池,不在你的请求结构里。

正确读中转日志

三行日志连在一起,就可以指认 ChatGPT Plus 5 小时窗口故障。按顺序找:

日志行它告诉你什么
openai_token_cache_get_failed account_id=16 error="redis: nil"中转读这个账号缓存 token 失败。通常是该账号被回收的第一个信号。
openai_chat_completions.upstream_failover_switching upstream_status=401 account_id=16中转尝试了这个账号,拿到 OpenAI 的 401,正在切到池里的下一个账号。
openai_chat_completions.account_select_failed error="no available accounts" excluded_account_count=0池子空了。0 表示在最终选择阶段没有任何账号被真正尝试过 — 中转在第二次选择之前就放弃了。

如果 excluded_account_count 大于 0,说明 failover 实际把所有账号都试了一遍,每个都被排除。如果是 0,说明中转连第二次选择都没启动。两个数字对应的是同一个根因:ChatGPT Plus 池子现在接不了你的请求。

客户端该怎么做

  1. 立刻停止紧贴重试。诊断期间把 max_retries=0。
  2. 并发量至少砍掉一半。窗口是按速率计算的,不是按请求数。
  3. 等滚动窗口慢慢恢复。恢复是渐进的 — 09:00 烧光预算的用户到 14:00 只是部分恢复,不是满血。
  4. 如果你的负载稳定且无法接受这个节奏,换到不同档位:付费 OpenAI API key 不和 Plus 5 小时窗口共用预算。
  5. 联系支持之前,先记下 request_id、UTC 时间、模型、中转返回的 "no available accounts" 响应体。把 API key 涂掉。
不要把 API key 贴到支持工单里。用 *** 代替。request_id 和中转的 account_select_failed 日志行是定位最强的两个线索。

运营侧该查什么

如果你运营这个中转,同样的生产模式给你的是一小组真正能做的事:

常见问题

什么是 ChatGPT Plus 的 5 小时窗口?

OpenAI 对 Plus 账号施加的一种滚动配额。官方文档没把精确预算写进错误面。实际表现:一个滑动窗口,单一 Plus 账号持续高负载下会被打到零。

为什么客户端收到的是 503 而不是 429?

中转吸收了 OpenAI Plus 的信号,上游 401 触发的 failover 把池子耗尽后,中转向客户端返回 503 "no available accounts"。

换模型能解决吗?

不能。窗口按账号计算,不按模型。同一个 Plus 账号,同一个窗口。

等满 5 小时会恢复吗?

窗口是滚动的。09:00 烧光预算的用户到 14:00 只是部分恢复,不是满血。恢复是渐进的。

看到 503 应该加大重试吗?

不应该。降并发,等滚动窗口恢复,或换到不同档位的账号。

服务端怎么确认?

找 upstream_failover_switching 的 upstream_status=401,后接 account_select_failed 的 error="no available accounts"。

这和直接收到 401 是一回事吗?

不是。客户端直接 401 说明你的 key 失效。在上游多次 401 之后收到 503 "no available accounts",说明你的 key 没问题,问题在中转的 Plus OAuth 池被耗尽。

相关教程

修复 503 "no available accounts"

OpenAI 兼容 API 账号池耗尽通用恢复清单。

打开页面

API 504 网关超时

区分反代定时器和上游变慢。

打开页面

429 限流修复

读懂 Retry-After,降并发,避免请求风暴。

打开页面

OpenAI 兼容客户端列表

对比 Codex CLI、Claude Code、Cline、Roo Code 等。

打开页面

API Key 排错

区分 401、404 和 model-not-found。

打开页面

联系支持

提交脱敏后的 request_id、模型和时延数据。

打开页面