MonkeyAI troubleshooting · ChatGPT Plus · OAuth pool

ChatGPT Plus 5-hour window: why the OAuth pool returns 503

If your OpenAI-compatible relay returns HTTP 503 with {"error":{"message":"Service temporarily unavailable","type":"api_error"}} and the relay logs say openai_chat_completions.account_select_failed error="no available accounts", the failure usually is not your key. It is the ChatGPT Plus OAuth pool rolling 5-hour window hitting zero on a single account while failover runs out of alternatives.

1,205503 responses on the OpenAI/ChatGPT Plus pool in 7 days (Aug 2 – Aug 8, 2026)
241account_id 16 upstream 401 switch events in 7 days
~30-40 / daystable daily cadence — not a one-off outage
0excluded_account_count on most failures — pool was empty, not rate-limited

What the rolling 5-hour window actually is

ChatGPT Plus accounts are subject to a rolling usage window that OpenAI resets on roughly a 5-hour cadence. The exact published budget is not part of OpenAI's documented error surface for API clients — there is no row for 504 or for "rolling window exhausted" on the OpenAI platform's Error codes guide. What you observe from the relay side is a moving quota that drops to zero on a single Plus account once sustained traffic passes through it.

The window is per-account, not per-model. Switching from one model to another on the same Plus OAuth login does not reset the timer, and it does not give you a fresh budget.

The OpenAI public error surface lists 401 / 403 / 429 / 500 / 503. A 504 from a relay points at the gateway, not the model. A 503 from the same relay after repeated upstream 401s points at the relay's account pool, not the upstream's documented quota.

Why your client gets 503, not 429

The relay does not surface OpenAI's internal quota signal as a 429 to your client. The chain we observed in production on Aug 7, 2026 looked like this:

# abbreviated relay log (actual lines from 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

Step by step:

  1. The relay picks a ChatGPT Plus account (account_id 16 in our logs) and forwards the request.
  2. OpenAI Plus returns 401 to the relay, meaning the rolling window is exhausted and the account's token is effectively revoked for inference traffic.
  3. The relay marks the account exhausted and tries failover — up to 10 switches in our observed config.
  4. Every other Plus account in the pool is in the same shape, so each switch returns 401 too.
  5. After the switch budget runs out, the relay returns 503 with a JSON body that mentions "no available accounts".

The relay absorbs the OpenAI Plus quota signal and translates it into its own 503. Your client never sees the upstream 401 directly.

Why this is different from a 401 to your client

What you seeWhere the failure livesWhere to look
401 JSON from the relay, body mentions invalid tokenYour key or headerAuthorization header, key prefix, account on the relay
404 from the relayRoute mismatchBase URL, endpoint path, model id
429 with structured body and Retry-AfterSingle-account quota on a healthy upstreamDrop concurrency; honor Retry-After
503 with "no available accounts" after upstream 401sRelay's Plus OAuth pool — rolling 5-hour windowServer log: upstream_failover_switching then account_select_failed
504 from the relayReverse-proxy timerproxy_read_timeout, route, upstream latency

A simple way to confirm before debugging your own config: /v1/models with the same key returns 200 with a JSON model list. If that route passes and /v1/chat/completions returns 503, the failure is in the inference account pool, not in your request shape.

Read the relay log the right way

Three log lines together pinpoint the ChatGPT Plus 5-hour window failure. Look for them in order:

Log lineWhat it tells you
openai_token_cache_get_failed account_id=16 error="redis: nil"The relay failed to read a cached token for that account. Often the first sign that an account is being recycled.
openai_chat_completions.upstream_failover_switching upstream_status=401 account_id=16The relay tried that account, got a 401 from OpenAI, and is moving to the next account in the pool.
openai_chat_completions.account_select_failed error="no available accounts" excluded_account_count=0The pool is empty. Zero means no account was even attempted at the final selection step — the relay gave up before re-trying.

If excluded_account_count is greater than zero, failover actually tried every account and each was excluded. If it is zero, the relay never even started a second selection cycle. Both numbers map to the same root cause: the ChatGPT Plus pool cannot serve the request right now.

What to do as a client

  1. Stop the tight retry loop. max_retries=0 for the duration of the diagnostic.
  2. Drop concurrency by at least half. The window is rate-based, not request-count-based.
  3. Wait for the rolling window. Recovery is gradual — a 09:00 burn gives partial recovery at 14:00, not full recovery.
  4. If your workload is steady and you cannot tolerate the cycle, switch to a different tier: an API key from a paid OpenAI API plan does not share the Plus 5-hour window.
  5. Capture request_id, UTC time, model, and the relay's "no available accounts" body before contacting support. Redact the API key.
Do not paste your API key into a support ticket. Replace it with ***. Capture the request_id and the relay's account_select_failed log line — those are the strongest lookup keys.

What an operator should check

If you operate the relay, the same production pattern gives you a smaller set of real actions:

FAQ

What is the ChatGPT Plus 5-hour window?

It is the rolling quota that OpenAI applies to a Plus account. The published budget is not part of OpenAI's documented error surface. Observable behavior: a moving window that drops to zero when traffic through a single Plus account is sustained.

Why does my client see 503 instead of 429?

The relay absorbs the OpenAI Plus signal. After upstream 401s and failover exhaustion, the relay answers the client with 503 "no available accounts".

Does rotating to a different model fix it?

No. The window is per-account, not per-model. Same Plus account, same window.

Will waiting 5 hours unblock it?

The window is rolling. A user who burned budget at 09:00 sees partial recovery at 14:00, not full recovery. Recovery is gradual.

Should I retry harder when I see this 503?

No. Drop concurrency, wait for the rolling window, or move to a different account tier.

How do I confirm it on the server side?

Look for upstream_failover_switching with upstream_status=401, followed by account_select_failed with error="no available accounts".

Is this the same as a 401 to my client?

No. A 401 to your client means your key is bad. A 503 "no available accounts" after upstream 401s means the gateway's Plus OAuth pool is the exhausted layer.

Related guides

Fix 503 "no available accounts"

General pool-exhaustion recovery checklist on an OpenAI-compatible API.

Open page

API 504 gateway timeout

Separate the proxy timer from a slow upstream.

Open page

429 rate limit fix

Read Retry-After, drop concurrency, and avoid request storms.

Open page

OpenAI-compatible clients list

Compare Codex CLI, Claude Code, Cline, Roo Code and others.

Open page

API key troubleshooting

Separate 401, 404 and model-not-found errors.

Open page

Contact support

Send redacted request_id, model and timing data.

Open page