anthropics / anthropics/claude-agent-sdk-python

Error context destroyed through exception flattening — CLI failures produce unhelpful 'Command failed with exit code 1'

Aberta
#798 1 comentário 0 reações 0 responsáveis Ver no GitHub
Linguagem predominante
Python
Estrelas
8.1k
Forks
1.3k
Merge médio
2d 31min
PRs com merge (30d)
1

Descrição

### SDK version
`claude-agent-sdk==0.1.56`

### Description

When the Claude CLI subprocess exits with a non-zero code, the SDK destroys all error context through a 3-step chain, making failures impossible to diagnose:

1. **`_internal/transport/subprocess_cli.py:614`** — `ProcessError` is created with `stderr="Check stderr output for details"` (hardcoded string, not actual stderr from the process)
2. **`_internal/query.py:250`** — Caught in `_read_task`, flattened via `str(e)`, sent as `{"type": "error", "error": str(e)}` through the message stream
3. **`_internal/query.py:726`** — `receive_messages()` re-raises as bare `Exception(message.get("error"))`, losing the `ProcessError` type entirely

Consumer code that catches `ClaudeSDKError` never fires because the exception arrives as bare `Exception`.

### Reproduction

Any scenario where the Claude CLI process exits with code 1 (permission denied, internal error, bad config). The consumer receives:

```
Exception: Command failed with exit code 1 (exit code: 1)
Error output: Check stderr output for details
```

No actual stderr, no typed exception, no actionable detail.

### Issues found (in order of severity)

| File | Line | Problem |
|------|------|---------|
| `subprocess_cli.py` | 616 | `stderr="Check stderr output for details"` is **hardcoded** — actual stderr is never captured into the error |
| `query.py` | 250 | `str(e)` flattens `ProcessError` (which has `exit_code`/`stderr` attrs) into a plain string |
| `query.py` | 726 | `raise Exception(...)` instead of preserving/re-raising original exception type — `except ClaudeSDKError` in consumer code never triggers |
| `query.py` | 207-209 | Control request errors also create bare `Exception` from dict |
| `subprocess_cli.py` | 446-449 | stderr reading exceptions silently swallowed (`except Exception: pass`) |
| `subprocess_cli.py` | 608 | `process.wait()` failure caught as `returncode = -1`, no logging |
| `query.py` | 272, 318, 334, 346, 385, 420 | Bare `Exception()` instead of typed `ClaudeSDKError` subclasses |

### Expected behavior

1. `ProcessError.stderr` should contain the **actual stderr output** from the CLI process, not a hardcoded string
2. `query.py:726` should raise `ProcessError` (or at minimum `ClaudeSDKError`), not bare `Exception` — so consumer `except ClaudeSDKError` blocks work
3. `query.py:250` should preserve the exception object (or at least its type and attributes) rather than stringifying it

### Workaround

Consumer code must catch `Exception` (not `ClaudeSDKError`) and try `getattr(exc, "exit_code", None)` defensively. But even that doesn't help here because the attributes are stripped at step 2 before re-raising.

### Environment

- Python 3.14.3
- claude-agent-sdk 0.1.56
- Windows 11
- Claude Code CLI installed via npm

Guia de contribuição

Nenhum guia de contribuição indexado para este repositório

Avaliação

Esta issue ainda não foi avaliada.

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.