Repository navigation
Description
Summary
The OpenAI Codex Responses endpoint can return an HTTP 200 SSE stream containing error and response.failed events with a structured transient-capacity error. Raven currently discards the event details and raises only:
Codex response failed
Because the original server_is_overloaded code/message is lost, Raven's shared error classifier categorizes the result as unknown instead of a retryable server failure. The user receives a generic terminal error without the normal backoff retry behavior.
Redacted evidence
A minimal OAuth-backed request returned:
http_status=200
event_type=error
event_error={
"type": "service_unavailable_error",
"code": "server_is_overloaded",
"message": "Our servers are currently overloaded. Please try again later."
}
event_type=response.failed
event_error={
"code": "server_is_overloaded",
"message": "Our servers are currently overloaded. Please try again later."
}
The user-visible result from Raven was:
Error calling Codex: Codex response failed
OAuth was still valid, and a standalone Codex CLI request using the same account succeeded during the same diagnostic window, so this was not a missing credential or expired-subscription condition.
Root cause
On current main, raven/providers/openai_codex_provider.py::_consume_sse() handles both event types with:
elif event_type in {"error", "response.failed"}:
raise RuntimeError("Codex response failed")This drops event.error and event.response.error. The provider then returns the generic text as an error response. LLMProvider.classify_error() cannot see overloaded, service unavailable, or the typed service-unavailable error, so it classifies the response as non-retryable unknown.
Steps to reproduce
- Configure a valid
openai_codexOAuth provider and model. - Call
raven doctor --probeor send an ordinary agent turn while the Codex endpoint is returning a capacity error. - Observe the SSE
error/response.failedevent withcode=server_is_overloaded. - Observe that Raven reports only
Codex response failedand does not classify it as a retryable server failure.
Expected behavior
- Preserve a safe, useful error code and message from the SSE event.
- Classify
server_is_overloaded/service_unavailable_erroras a transient server failure. - Use Raven's existing retry/backoff ladder.
- Show an actionable final message if retries are exhausted.
Suggested fix scope
- Extract error details from
event.errorandevent.response.errorin_consume_sse(). - Raise or return an error that preserves
type,code, andmessagewithout exposing credentials or request content. - Ensure the existing classifier sees
server_is_overloadedorservice unavailableand marks the failure retryable. - Add regression tests for:
errorwithservice_unavailable_error;response.failedwithserver_is_overloaded;- backoff retry followed by success;
- retry exhaustion returning the real, safe message;
- unrelated non-retryable SSE failures.
Environment
- macOS arm64
- Raven CLI v0.1.3 locally
- Confirmed that the same generic SSE error handling remains on current
main
Privacy
This report contains no OAuth tokens, account identifiers, usernames, private paths, images, chat content, or business files.
Activity
AmirF194 commentedon Jul 31, 2026
Reproduced at HEAD
16bdca7din a cleanpython:3.12-slimcontainer (httpx + loguru installed directly, no OAuth or network needed): built anhttpx.Responsecarrying the two SSE events from the report's redacted evidence (type: errorandtype: response.failed, bothcode: server_is_overloaded) and ran it through_consume_sse()andOpenAICodexProvider.classify_error()directly.Matches the report exactly.
_consume_sse()(openai_codex_provider.py:325-326) dropsevent["error"]andevent["response"]["error"]and raises a fixed string, soclassify_error()(base.py:298-414) has nothing to match against itsoverloaded/service unavailablesubstrings and falls through to theunknownbucket at:414, which is non-retryable by default.git log -G 'Codex response failed' --followon this file returns only the initial commit, so this looks unimplemented rather than a deliberate choice.fancyboi999 commentedon Aug 4, 2026
Hi, I'd like to work on this issue.
I reproduced the current behavior on the latest
mainwithout OAuth or a network call: a synthetic HTTP 200 SSEresponse.failedevent containingservice_unavailable_errorandserver_is_overloadedis reduced toRuntimeError("Codex response failed"), then classified asunknownwith retry and fallback disabled.My planned scope is:
type,code, andmessagefields from botherrorandresponse.failedevents without serializing the full event;make cigate.Please let me know if there is a preferred error representation or another implementation already in progress.
feat(providers): endpoint failover and provider path close-out (EverM…
feat(providers): endpoint failover and provider path close-out (EverM…