Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/claude_agent_sdk/_internal/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
ToolPermissionContext,
)
from .transport import Transport
from .._errors import ProcessError

if TYPE_CHECKING:
from mcp.server import Server as McpServer
Expand Down Expand Up @@ -217,6 +218,21 @@ async def _read_messages(self) -> None:
# Task was cancelled - this is expected behavior
logger.debug("Read task cancelled")
raise # Re-raise to properly handle cancellation
except ProcessError as e:
# The CLI can exit non-zero after delivering a valid result (e.g.,
# StructuredOutput tool_use triggers exit code 1). When we already
# received a result message, treat the process error as non-fatal.
if self._first_result_event.is_set():
logger.warning(
f"Process exited with code {e.exit_code} after result — ignoring"
)
else:
logger.error(f"Process error before result: {e}")
for request_id, event in list(self.pending_control_responses.items()):
if request_id not in self.pending_control_results:
self.pending_control_results[request_id] = e
event.set()
await self._message_send.send({"type": "error", "error": str(e)})
except Exception as e:
logger.error(f"Fatal error in message reader: {e}")
# Signal all pending control requests so they fail fast instead of timing out
Expand Down