Hmbown/CodeWhale · error

Responses API error (HTTP {status}): {raw}

Error message

Responses API error (HTTP {status}): {raw}

What it means

The OpenAI Responses API request returned a non-2xx status. The body is read bounded (`bounded_error_text` up to `ERROR_BODY_MAX_BYTES`) and embedded raw (unlike the chat route, no sanitization pass here), and the status is recorded via `record_provider_response`. Transport-level failures to even send the request surface separately as "Responses API request failed" via `.context`.

Source

Thrown at crates/tui/src/client/responses.rs:191

                            .header("OpenAI-Beta", "responses=experimental")
                            .header("originator", "codex_cli_rs");
                        if let Some(account_id) = &account_id {
                            builder = builder.header("chatgpt-account-id", account_id);
                        }
                    }
                    builder.body(request_body.clone())
                })
                .await
                .context("Responses API request failed")
            }
        })
        .await?;

        let status = response.status();
        crate::client::record_provider_response(self.api_provider, status.as_u16());
        if !status.is_success() {
            let raw = bounded_error_text(response, ERROR_BODY_MAX_BYTES).await;
            anyhow::bail!("Responses API error (HTTP {status}): {raw}");
        }

        let stream_idle_timeout = self.stream_idle_timeout;
        let byte_stream = response.bytes_stream();

        let stream = async_stream::stream! {
            use futures_util::StreamExt;

            // Emit synthetic MessageStart.
            yield Ok(StreamEvent::MessageStart {
                message: MessageResponse {
                    id: String::new(),
                    r#type: "message".to_string(),
                    role: "assistant".to_string(),
                    content: vec![],
                    model: wire_model.clone(),
                    stop_reason: None,
                    stop_sequence: None,

View on GitHub (pinned to 8880682c63)

Solutions

  1. Read the HTTP status and raw body first — the provider message identifies the exact cause
  2. 401/403: fix the API key and its Responses API access
  3. 429: back off and retry; reduce request rate
  4. 400/404: correct the model id, base URL, and request fields per the body text
Defensive patterns

Strategy: retry

Type guard

fn is_retryable_http_status_from_message(msg: &str) -> bool {
    [408, 409, 429, 500, 502, 503, 504]
        .iter()
        .any(|s| msg.contains(&format!("HTTP {s}")))
}

Try / catch

match client.send_responses(request).await {
    Err(e) if is_retryable_http_status_from_message(&e.to_string()) => {
        backoff_retry(client, request, MAX_ATTEMPTS).await
    }
    Err(e) if e.to_string().contains("HTTP 401") || e.to_string().contains("HTTP 403") => {
        Err(e) // credentials/access: fix the key, never retry
    }
    result => result,
}

Prevention

When it happens

Trigger: 401 invalid API key; 404 unknown model or wrong base URL; 400 invalid parameters per the embedded message; 429 rate limit/quota; 5xx provider errors.

Common situations: Expired or mistyped OpenAI key; requesting a deprecated or nonexistent model id; Responses API not enabled for the account/key; bursts hitting org rate limits.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/cef81aab07305fbd. Report an issue: GitHub.