waiting_for_human) or a stop condition (stopped) is not an error: both return a normal result. Which failures also send a run.failed event differs by language, so don’t rely on the event alone to detect a failure.
How a failed run surfaces
Which events fire when something fails
Lifecycle hooks lists every event.
Find the cause of an error
TypeScript error types
AgentGatewayError has status, statusText, headers, body, requestId, generationId, reason, errorType, errorOrigin, failedProviders, failedStatuses and routing diagnostics. Failed runs and steps keep the same details in errorDetails. A failure partway through a streamed response is an AgentStreamError, a subclass with code and retryable.
AgentSchemaValidationError has a target of tool_input, tool_output, tool_event or agent_output, and details with the validator’s error. Treat these as contract failures, not transient model failures.
To classify any error, for example in modelRetry.retryOn, use agentErrorIsRetryable(error), agentRetryAfterMs(error) and agentErrorIsContextOverflow(error).
Rust error type
Every runtime failure is anAgentError; read it with message(). Gateway PhaseoError values are converted into AgentError, so if you need the original gateway status and body, call the phaseo client directly or implement a custom ModelClient that keeps them.
Recover from tool errors
By default a tool error fails the run. Set the tool’s error policy toreturn-to-model when the model can sensibly try something else: the error becomes the tool result {"error": "..."} and the run continues. Keep the default, fail-run, for unsafe or unrecoverable failures.
Handle cancellation and timeouts
A tool timeout or cancellation doesn’t always stop the tool’s own work. Give HTTP, database and process calls inside tools their own deadlines, and treat a cancelled or timed-out run as finished unless your application starts a new one.Recover from an interrupted TypeScript run
If a run crashed or was cancelled mid-step, its history can hold tool calls without results, which providers reject. TypeScript’scontinueRun() answers them as not run and sends history.repaired. Call repairToolHistory(messages) yourself if you reuse the messages elsewhere.
Check these first
PHASEO_API_KEYreaches the process and is passed to the gateway client.- Every tool has a unique, stable ID.
- Approvals, rejections and tool outputs use exact tool-call IDs, and a human input message is never a substitute for a tool output.
- The whole run result is saved before you show an approval UI or hand control to another request or worker.
- Validators are deterministic and free of side effects, so a failed check can be retried safely.
- Model retries are bounded; validation and approval failures shouldn’t be retried blindly.
step.started, model.requested and tool.failed with lifecycle hooks, and see Observability for the IDs that tie a step to gateway logs.