anthropics / anthropics/claude-agent-sdk-python

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

未关闭
#798 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
Python
星标
8.1k
派生
1.3k
平均合并
2 天 31 分钟
30 天内合并 PR
1

描述

### 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

贡献指南

这个仓库没有索引到贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。