anthropics / anthropics/claude-agent-sdk-python

ClaudeSDKClient can leak transports on double connect and pre-Query failures

オープン
#1,161 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
Python
スター
8.1k
フォーク
1.3k
PR マージ指標
PR 指標を取得中

説明

### Summary

Transport ownership is lost in two related connection lifecycle paths:

1. Calling `ClaudeSDKClient.connect()` twice overwrites the first live `Query` and transport without closing them.
2. An exception after `transport.connect()` but before a `Query` is assigned causes cleanup to discard the transport reference without closing it.

### Affected code

- `src/claude_agent_sdk/client.py:100-145`
- `src/claude_agent_sdk/client.py:187-229`
- `src/claude_agent_sdk/client.py:612-621`
- `src/claude_agent_sdk/_internal/client.py:127-174`
- `tests/test_streaming_client.py:1123-1141`

### Current behavior

`connect()` has no already-connected guard. A second call creates a new transport and assigns a new `Query`. The existing test only asserts that two transports were created; it does not assert that the first was closed.

For failures before `self._query = Query(...)`, the outer exception handler calls `disconnect()`. However, `disconnect()` only closes through `self._query`; when that is still `None`, it sets `self._transport = None` without calling `close()`.

One reachable example is an invalid `CLAUDE_CODE_STREAM_CLOSE_TIMEOUT`: integer conversion occurs after the subprocess connects but before Query construction.

The one-shot InternalClient has a similar ownership gap because `await chosen_transport.connect()` occurs before the `try/finally` that closes `query`.

### Why this matters

The abandoned transport can retain a CLI subprocess, stdin/stdout pipes, and background read tasks. Repeated failures or reconnect attempts can accumulate orphan processes and active sessions.

### Expected behavior

Every successfully or partially connected transport must have exactly one owner and must be closed on replacement or failure.

### Possible fix

- Reject a second `connect()` with `CLIConnectionError`, or explicitly disconnect the old connection before replacing it.
- Wrap the period between transport creation/connect and Query ownership transfer in a transport-level `try/finally`.
- Add assertions that the first transport is closed on double connect and that a connected transport is closed when setup fails before Query construction.

PR #1082 mentions the pre-Query transport gap as deliberately out of scope, but I could not find a dedicated issue or active fix for it.

### Environment

- Repository revision: current `main` audit at SDK version 0.2.128
- Bundled CLI version: 2.1.220
- Python test suite: 1,291 passed, 5 skipped
- Ruff and mypy: clean

I searched the existing issues and pull requests using the affected symbols and behavior before filing this.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。