anthropics / anthropics/claude-agent-sdk-python
[BUG] API errors are returned as text messages instead of raised as exceptions
- Lingua principale
- Python
- Stelle
- 8.1k
- Fork
- 1.3k
- Merge medio
- 2g 31m
- PR unite (30g)
- 1
Descrizione
# API errors are returned as text messages instead of raised as exceptions
## Summary
API errors from the Anthropic API (including 400 Bad Request, 401 Authentication, 429 Rate Limit, 529 Overloaded, etc.) are being returned as text messages in the chat stream instead of being raised as exceptions. This makes it impossible for applications to programmatically handle API errors.
## Impact
**Critical**: Applications cannot catch and handle API errors, leading to:
- Errors appearing as chat messages to end users
- No ability to implement retry logic for transient errors (529 Overloaded)
- No way to detect authentication failures programmatically
- Invalid configurations (wrong model names) appearing as chat responses
## Reproduction
### Example 1: Invalid Model Identifier
```python
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
async def test_invalid_model():
options = ClaudeAgentOptions(
model="claude-opus-4-5-20251101" # Invalid model name
)
async with ClaudeSDKClient(options=options) as client:
await client.query("Hello")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
print(message.content[0].text)
# Prints: "API Error (claude-opus-4-5-20251101): 400 The provided model identifier is invalid."
# Expected: anthropic.BadRequestError exception
```
### Example 2: API Overload (529)
```python
async def test_overload():
async with ClaudeSDKClient() as client:
await client.query("Some request during high load")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
print(message.content[0].text)
# Prints: "API Error: Repeated 529 Overloaded errors"
# Expected: anthropic.RateLimitError or similar exception
```
## Expected Behavior
API errors should be raised as exceptions, similar to how the Anthropic Python SDK works:
```python
try:
response = await client.messages.create(...)
except anthropic.BadRequestError as e:
# Handle invalid request (400)
except anthropic.AuthenticationError as e:
# Handle auth failure (401)
except anthropic.RateLimitError as e:
# Handle rate limit (429)
except anthropic.InternalServerError as e:
if e.status_code == 529:
# Handle overload with retry logic
```
## Actual Behavior
All API errors are returned as `AssistantMessage` objects with:
1. Error text in `message.content[0].text` (e.g., "API Error: ...")
2. Error type in `message.error` field (e.g., `"rate_limit"`, `"invalid_request"`)
3. **No exception is raised**
The `error` field exists on `AssistantMessage` but is never checked or used to raise exceptions.
## Root Cause Analysis
Based on code investigation, the issue occurs in the message parsing flow:
### 1. Message Parser ([`message_parser.py:91-127`](https://github.com/anthropics/claude-agent-sdk-python/blob/main/src/claude_agent_sdk/_internal/message_parser.py#L91-L127))
```python
case "assistant":
try:
content_blocks: list[ContentBlock] = []
for block in data["message"]["content"]:
match block["type"]:
case "text":
content_blocks.append(TextBlock(text=block["text"]))
# ❌ No error detection here!
return AssistantMessage(
content=content_blocks,
model=data["message"]["model"],
parent_tool_use_id=data.get("parent_tool_use_id"),
error=data["message"].get("error"), # ✓ Error field is set
)
# ❌ But no exception is raised!
```
### 2. The Error Field is Never Checked
Searching the entire codebase:
```bash
$ grep -r "\.error" --include="*.py" src/
# Only definition found, no usage!
src/claude_agent_sdk/types.py: error: AssistantMessageError | None = None
```
**No code in the SDK checks the `error` field on `AssistantMessage` objects.**
### 3. Flow Diagram
```
Anthropic API returns error (400/429/529/etc.)
↓
Claude CLI receives error and creates assistant message:
{
"type": "assistant",
"message": {
"content": [{"type": "text", "text": "API Error: ..."}],
"error": "rate_limit", # Error type stored here
"model": "claude-sonnet-4-5"
}
}
↓
SDK parses message (message_parser.py)
↓
Creates AssistantMessage:
content=[TextBlock("API Error: ...")]
error="rate_limit" # Field is set but never checked!
↓
Returns to user as normal message (NO EXCEPTION) ❌
```
## Related Issues
This bug manifests in multiple scenarios reported in other issues:
1. **#437** - SDK swallows API error messages (related to error message clarity)
2. **#431** - "API Error: 400 Input is too long for requested model" - no programmatic way to handle
3. **#8217** (claude-code) - WebFetch 400 model identifier error appears as text
4. **#307** - Bedrock region mismatch errors appear as text
## Environment
- **SDK Version**: 0.1.18+ (observed in latest)
- **Python Version**: 3.12
- **OS**: Linux, macOS (production environments)
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Valutazione
Questa issue non è ancora stata valutata.