Summary
src/claude_agent_sdk/_internal/transcript_mirror_batcher.py:90-91:
self._flush_task = asyncio.ensure_future(self._drain())
self._flush_task.add_done_callback(lambda t: t.exception())
The intent is "swallow the task's exception so asyncio doesn't warn about unretrieved exceptions". But in Python 3.8+, Task.exception() on a cancelled task raises CancelledError. The lambda doesn't handle it, so asyncio's callback machinery logs Exception in callback <lambda> with a CancelledError traceback every time an in-flight eager-flush task is cancelled.
Where this fires
Whenever an eager-flush task is in flight at cancellation time:
Reproducer
The traceback in #928 shows the exact symptom from a normal pytest run:
ERROR asyncio: Exception in callback TranscriptMirrorBatcher.enqueue.<locals>.<lambda>(<Task cancell...>)
File ".../transcript_mirror_batcher.py", line 91, in <lambda>
self._flush_task.add_done_callback(lambda t: t.exception())
^^^^^^^^^^^^^
asyncio.exceptions.CancelledError
Impact
Log noise during normal cancellation paths. Doesn't affect functionality — the _drain task itself handles cancellation correctly via the async with self._lock. But the noise pollutes test output and production logs whenever the SDK shuts down with pending eager flushes (the entire point of session_store_flush="eager").
Suggested fix
Skip cancelled tasks before calling exception():
def _swallow_done_exception(t: asyncio.Task[None]) -> None:
if t.cancelled():
return
t.exception() # Retrieve to silence "Task exception was never retrieved"
self._flush_task.add_done_callback(_swallow_done_exception)
Equivalent one-liner:
self._flush_task.add_done_callback(
lambda t: None if t.cancelled() else t.exception()
)
Environment
- claude-agent-sdk-python @
9aafd84 (current main)
- Python 3.11.14
Summary
src/claude_agent_sdk/_internal/transcript_mirror_batcher.py:90-91:The intent is "swallow the task's exception so asyncio doesn't warn about unretrieved exceptions". But in Python 3.8+,
Task.exception()on a cancelled task raisesCancelledError. The lambda doesn't handle it, so asyncio's callback machinery logsException in callback <lambda>with aCancelledErrortraceback every time an in-flight eager-flush task is cancelled.Where this fires
Whenever an eager-flush task is in flight at cancellation time:
Captured log teardownblock, which is this bug, not the actual test failure).Query.close()cancelling child tasks while a drain is mid-flight.Reproducer
The traceback in #928 shows the exact symptom from a normal pytest run:
Impact
Log noise during normal cancellation paths. Doesn't affect functionality — the
_draintask itself handles cancellation correctly via theasync with self._lock. But the noise pollutes test output and production logs whenever the SDK shuts down with pending eager flushes (the entire point ofsession_store_flush="eager").Suggested fix
Skip cancelled tasks before calling
exception():Equivalent one-liner:
Environment
9aafd84(currentmain)