Skip to content

Handle errors and cancel turns

Turns can fail (the LLM rejected the request, a tool errored repeatedly) or be cancelled by the user. The event stream tells you which. This guide covers both paths.

Failures surface as turn.failed events:

async for event in client.events.stream(session.id):
if event.type == "turn.completed":
break
if event.type == "turn.failed":
err = event.data.get("error", "unknown")
print(f"Turn failed: {err}")
break

The error field is a structured object — type, message, optional cause. Inspect it to decide whether to retry, surface to the user, or escalate.

To cancel a turn that’s already running:

import asyncio
await client.messages.create(session.id, "Analyse every Python package on PyPI")
await asyncio.sleep(2)
await client.sessions.cancel(session.id)

Cancellation emits a turn.cancelled event, appends a user message noting the cancellation, and the worker emits a final agent message confirming the work was stopped. The session itself stays open and accepts new messages.

TERMINAL = {"turn.completed", "turn.failed", "turn.cancelled"}
async for event in client.events.stream(session.id):
if event.type in TERMINAL:
print(f"[{event.type}]")
if event.type == "turn.failed":
print(event.data.get("error"))
break

Failed turns don’t auto-retry from the application’s perspective (durable execution retries individual steps inside a turn, not the whole turn). To retry, send the message again:

async def send_with_retry(client, session_id, content, attempts=2):
for attempt in range(attempts):
await client.messages.create(session_id, content)
async for event in client.events.stream(session_id):
if event.type == "turn.completed":
return True
if event.type == "turn.failed":
if attempt == attempts - 1:
return False
break
return False

Don’t retry indefinitely — a turn that fails twice usually fails for a reason (rate limit, malformed prompt, missing capability). Surface to the user.

Event payloadCauseAction
rate_limit_exceededLLM provider rate-limited the workerWait, retry with backoff
request_too_largeContext overflowed even after compactionTrim the conversation, start a fresh session
tool_call_failed (terminal)A tool errored repeatedlyInspect tool result events, fix the agent prompt or tool config
cancelledUser or app called sessions.cancelNo retry — user intent