anthropics / anthropics/anthropic-sdk-python

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

Đang mở
#1,918 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Python
Star
3.9k
Fork
853
Merge trung bình
1 ngày 18 giờ
Pull request đã merge (30 ngày)
11

Mô tả

**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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.