Symptom
If the AsyncIterable passed as prompt= to query() raises — a bug in the caller's generator, or a message that fails json.dumps — the exception is logged at debug level and discarded. Stdin stays open, the CLI keeps waiting for input that will never arrive, no result is ever produced, and query() blocks forever. There is no error, no timeout, nothing — from the caller's perspective the SDK just stops.
Mechanism
Query.stream_input (src/claude_agent_sdk/_internal/query.py:829):
try:
async for message in stream:
if self._closed:
break
await self.transport.write(json.dumps(message) + "\n")
await self.wait_for_result_and_end_input()
except Exception as e:
logger.debug(f"Error streaming input: {e}")
On any exception the task exits without calling end_input() and without telling anyone. The consumer is blocked in receive_messages(); the CLI is blocked on stdin; neither side can make progress.
Repro (real CLI, SDK 0.2.116, CLI 2.1.207)
Two variants, both verified against the live CLI with a 45s watchdog:
- Generator raises before yielding anything →
query() yields 0 messages and hangs until the watchdog kills it (would hang forever otherwise).
- Generator yields one valid message, first turn completes normally (assistant + result arrive), then raises →
query() hangs after the healthy-looking turn.
In both cases the only trace of the ValueError is an invisible debug log line.
Suggested fix
Outside teardown (self._closed), the failure should: log at error level, close stdin (end_input()) so the CLI can wind down, and push an {"type": "error"} message into the message stream — the same mechanism _read_messages already uses — so receive_messages() raises promptly.
PR incoming with this fix + a regression test (fails on main via bounded timeout, passes with the fix). After the fix, both real-CLI repros above raise Error streaming input: ... within seconds instead of hanging.
Symptom
If the
AsyncIterablepassed asprompt=toquery()raises — a bug in the caller's generator, or a message that failsjson.dumps— the exception is logged at debug level and discarded. Stdin stays open, the CLI keeps waiting for input that will never arrive, no result is ever produced, andquery()blocks forever. There is no error, no timeout, nothing — from the caller's perspective the SDK just stops.Mechanism
Query.stream_input(src/claude_agent_sdk/_internal/query.py:829):On any exception the task exits without calling
end_input()and without telling anyone. The consumer is blocked inreceive_messages(); the CLI is blocked on stdin; neither side can make progress.Repro (real CLI, SDK 0.2.116, CLI 2.1.207)
Two variants, both verified against the live CLI with a 45s watchdog:
query()yields 0 messages and hangs until the watchdog kills it (would hang forever otherwise).query()hangs after the healthy-looking turn.In both cases the only trace of the
ValueErroris an invisible debug log line.Suggested fix
Outside teardown (
self._closed), the failure should: log at error level, close stdin (end_input()) so the CLI can wind down, and push an{"type": "error"}message into the message stream — the same mechanism_read_messagesalready uses — soreceive_messages()raises promptly.PR incoming with this fix + a regression test (fails on main via bounded timeout, passes with the fix). After the fix, both real-CLI repros above raise
Error streaming input: ...within seconds instead of hanging.