Skip to main content
Failures in a Research Agent or Workflows request fall into two layers, and they require different handling. HTTP-level errors arrive before the SSE stream starts and surface as conventional HTTP status codes. Stream-level errors arrive inside the SSE stream as typed messages and may or may not terminate the request. This guide covers both, and the recommended response for each.

HTTP-level errors

These are returned by the API before any SSE event is emitted. The response body is typically a JSON object with a detail field (for validation errors) or a plain error message. Your HTTP client should check the response status before consuming the stream. Use a small wrapper such as response.raise_for_status() (in Python’s requests) to convert HTTP errors into exceptions before entering the streaming loop. Trying to consume the SSE stream from a non-2xx response will silently produce zero events.

Stream-level errors

Once the HTTP response is established with a 2xx status, errors are delivered as typed messages inside the stream. Three message types matter:

LLM_RETRY

The agent’s upstream LLM call hit a transient failure (rate limit, timeout, short-lived error) and is being retried automatically. The stream will resume without further action.
Consumers should not act on this event other than emitting a debug-level log line. There is no user-facing surface beyond an optional “agent is retrying…” indicator.

TOOL_ERROR

A specific tool failed. The tool_name field identifies which one. The agent will continue, possibly calling a different tool or synthesizing without that source. Most integrations log these events and only surface a user-visible warning if the final answer is materially degraded (for example, if every search call failed).
A common pattern is to count TOOL_ERROR events per tool name and, if the count exceeds a threshold during the same request, surface a soft warning at the end (“Some sources could not be retrieved; the answer may be incomplete.”).

ERROR

The request cannot continue. The stream terminates immediately after this event; no COMPLETE will follow. Surface the error to the user and stop reading the stream.
The error field is a human-readable string suitable for logging, but not always suitable for direct display to end users. Wrap it in your own UX-friendly message where appropriate.

Worked example: error-aware streaming handler

The handler below distinguishes HTTP-level failures, stream-level errors, and informational retries. It logs per-event details and only raises when the request can no longer succeed.
This handler intentionally distinguishes:
  • Pre-stream HTTP errors — raised immediately so callers do not waste cycles reading an empty stream.
  • In-stream recoverable events — logged at appropriate levels but never raised.
  • In-stream fatal events — raised so callers can surface the failure.
  • Truncated streams — detected by the absence of a COMPLETE event, preventing silent “empty answer” bugs.

Retry and backoff

For 429 and 5xx HTTP responses, exponential backoff with jitter is the safe default:
Do not retry on 400, 401, 403, or 404: those reflect client-side or identity problems that will not resolve on retry. In-stream events do not benefit from retry at the request level. LLM_RETRY and TOOL_ERROR already represent the agent’s own internal retry behavior; the request is doing the right thing without your help.

When to abort versus continue

Next steps

Streaming responses

Full reference for every message type the stream may emit.

Conversation continuity

Recover from a 404 on from_checkpoint_id by resetting the thread.