HKUDS/DeepTutor · error · CodexHTTPError

{friendly_error(response.status_code)}

Error message

{friendly_error(response.status_code)}

What it means

When the Codex SSE endpoint returns a non-success HTTP status, _request_codex raises CodexHTTPError with a friendly, status-specific message; the raw body (first 500 bytes) is logged at debug level so operators can diagnose without leaking it to users.

Source

Thrown at deeptutor/services/llm/provider_core/openai_codex_provider.py:227

async def _request_codex(
    url: str,
    headers: dict[str, str],
    body: dict[str, Any],
    verify: bool,
    on_content_delta: Callable[[str], Awaitable[None]] | None = None,
) -> tuple[str, list[ToolCallRequest], str]:
    async with httpx.AsyncClient(timeout=60.0, verify=verify) as client:
        async with client.stream("POST", url, headers=headers, json=body) as response:
            if response.status_code != 200:
                raw = await response.aread()
                # Kept out of the reply the learner sees, but an operator cannot
                # diagnose an upstream rejection without the body.
                logger.debug(
                    "Codex API returned HTTP {}: {}",
                    response.status_code,
                    raw.decode("utf-8", "ignore")[:500],
                )
                raise CodexHTTPError(
                    response.status_code,
                    _friendly_error(response.status_code),
                )
            return await consume_sse(response, on_content_delta)


def _prompt_cache_key(messages: list[dict[str, Any]]) -> str:
    raw = json.dumps(messages, ensure_ascii=True, sort_keys=True)
    return hashlib.sha256(raw.encode("utf-8")).hexdigest()


def _friendly_error(status_code: int) -> str:
    if status_code == 401:
        return "Codex login expired. The session was refreshed; retry this request."
    if status_code == 403:
        return "This Codex account is not allowed to make the requested call."
    if status_code == 429:
        return "Codex usage quota exceeded or rate limit triggered. Please try again later."

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Match the friendly message to the status: 429 → back off and retry; 401 → re-login; 5xx → retry later.
  2. Enable debug logging to see the truncated response body.
  3. Check model name and request size if errors are consistent.
Defensive patterns

Strategy: retry

Try / catch

try:
    resp = await provider.chat(messages)
except CodexHTTPError as e:
    if e.status_code == 429:
        await asyncio.sleep(backoff()); retry()
    elif e.status_code >= 500:
        retry_later()
    else:
        raise  # 4xx needs user action

Prevention

When it happens

Trigger: chat/chat_stream → _call_codex → _request_codex receives e.g. 401 (expired token), 429 (rate limit), 5xx (upstream failure).

Common situations: Rate limits during heavy usage; expired session tokens; OpenAI-side incidents; malformed model names producing 404.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/370f9d022a2832c0. Report an issue: GitHub.