anthropics / anthropics/anthropic-sdk-python

Mid-stream `error` events still raise `APIStatusError` with `status_code=200` (#1258 closed without a fix)

Abierto
#1,918 0 comentarios 0 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
Python
Estrellas
3.9k
Forks
853
Merge medio
1 d 18 h
PR fusionados (30 d)
11

Descripción

**Correction (same day):** #1258 was not closed without a fix. #1587 added `APIStatusError.type`, which carries the in-stream error type (`overloaded_error` here), and the maintainers chose that over synthesizing a status code. What this issue is really about is the class: an in-stream error is still the bare `APIStatusError`, never `OverloadedError` / `RateLimitError`, so class-based handling misses it. The status code staying 200 is by design. PR that only picks the class from `error.type`: https://github.com/anthropics/anthropic-sdk-python/pull/1921

---

Follow-up to #1258, closed as completed on 2026-03-31. The behaviour is unchanged on 0.122.0, 1.4.0 and main.

When the API sends an `error` event inside a stream, `_streaming.py` passes the original 200 response to `_make_status_error`, which dispatches on `response.status_code` only, so the result is a bare `APIStatusError` with `status_code=200`. For an `overloaded_error` that means `OverloadedError` (529) is never raised in-stream, and anything that keys retries on the exception class or the status code sees a 200 "error". Wrappers end up with `"overloaded_error" in str(e)` (agno does exactly that) because nothing else is stable.

Offline repro, no network:

```python
import platform
import sys

import anthropic

try:
import httpx2 as httpx # anthropic >= 1.0
except ImportError:
import httpx

SSE = (
'event: message_start\ndata: {"type":"message_start","message":{"id":"msg_1","type":"message","role":"assistant","model":"claude-sonnet-4-6","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":1,"output_tokens":0}}}\n\n'
'event: error\ndata: {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}\n\n'
)

def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(200, headers={"content-type": "text/event-stream"}, content=SSE.encode())

client = anthropic.Anthropic(api_key="x", http_client=httpx.Client(transport=httpx.MockTransport(handler)), max_retries=0)
print(f"python {sys.version.split()[0]} {platform.system()}, anthropic {anthropic.__version__}")
try:
with client.messages.stream(model="claude-sonnet-4-6", max_tokens=8, messages=[{"role": "user", "content": "hi"}]) as s:
for _ in s:
pass
except anthropic.APIStatusError as e:
print(f"raised {type(e).__name__} status_code={e.status_code} body={e.body}")
print(f"has OverloadedError class: {hasattr(anthropic, 'OverloadedError')}")
```

Output on 0.122.0 and 1.4.0 (python 3.12.13, macOS):

```
raised APIStatusError status_code=200 body={'type': 'error', 'error': {'type': 'overloaded_error', 'message': 'Overloaded'}}
has OverloadedError class: True
```

Expected: the in-stream error mapped from `body["error"]["type"]` (overloaded_error to `OverloadedError` / 529, rate_limit_error to `RateLimitError` / 429, api_error to `InternalServerError` / 500, and so on), with the 200 response still attached. #1263 and #1269 did roughly that and were closed unmerged. Happy to send a fresh PR in whatever shape the "better approach" mentioned in #1258 was meant to take.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.