From e8fa63646a8379bebd5bfadae587aa97cb617303 Mon Sep 17 00:00:00 2001 From: Maxwell Calkin Date: Sun, 8 Mar 2026 17:27:32 -0400 Subject: [PATCH] fix: clean up resources in Query.close() to prevent memory leaks The close() method cancels the task group and closes the transport, but does not clear hook_callbacks, pending_control_responses, pending_control_results, or close the memory object streams. In long-running applications or those creating multiple Query instances, these orphaned references prevent garbage collection and cause memory leaks. Add cleanup calls after transport.close() to clear all dictionaries and explicitly close both ends of the anyio memory object stream. Co-Authored-By: Claude Opus 4.6 --- src/claude_agent_sdk/_internal/query.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/claude_agent_sdk/_internal/query.py b/src/claude_agent_sdk/_internal/query.py index bd7512e0..508b4865 100644 --- a/src/claude_agent_sdk/_internal/query.py +++ b/src/claude_agent_sdk/_internal/query.py @@ -665,6 +665,14 @@ async def close(self) -> None: with suppress(anyio.get_cancelled_exc_class()): await self._tg.__aexit__(None, None, None) await self.transport.close() + # Clean up resources to prevent memory leaks in long-running applications + self.hook_callbacks.clear() + self.pending_control_responses.clear() + self.pending_control_results.clear() + with suppress(Exception): + await self._message_send.aclose() + with suppress(Exception): + await self._message_receive.aclose() # Make Query an async iterator def __aiter__(self) -> AsyncIterator[dict[str, Any]]: