Agent error handling
Genkit agent failures have different recovery paths depending on when they happen. A request can be rejected before an invocation starts, a turn can fail after state has been loaded, or a tool can return a domain-level result that the model can handle.
Failure categories
Section titled “Failure categories”- Rejected init returns a non-nil Go error from
Connect,Run, orRunText. Fix the caller or selected resume source. - Failed turns return
AgentOutputwithFinishReasonFailedandError. Resume fromStatefor client-managed agents orSnapshotIDfor server-managed agents. - Tool domain problems should return structured tool output when the coordinator or model can recover.
- Background failures appear as snapshot status
failed,aborted, orexpired. Inspect snapshot error details or retry from a completed snapshot.
Check both error channels
Section titled “Check both error channels”import aix "github.com/firebase/genkit/go/ai/exp"out, err := agent.RunText(ctx, "Look up order 123.")if err != nil { return fmt.Errorf("agent invocation did not start: %w", err)}
if out.FinishReason == aix.AgentFinishReasonFailed { if out.Error != nil { return fmt.Errorf("agent turn failed: %s: %s", out.Error.Status, out.Error.Message) } return fmt.Errorf("agent turn failed")}
fmt.Println(out.Message.Text())A non-nil Go error means the invocation was rejected or could not produce an output. A failed turn is in-band so the output can include recovery state or a recovery snapshot ID.
Resume after failure
Section titled “Resume after failure”For client-managed agents, pass the last-good state from the failed output:
retry, err := agent.RunText(ctx, "Try order 456.", aix.WithState(out.State),)For server-managed agents, resume from the recovery snapshot:
retry, err := agent.RunText(ctx, "Try order 456.", aix.WithSnapshotID[OrderState](out.SnapshotID),)Only completed snapshots are resumable. If the latest session snapshot is failed, aborted, or pending, use a known completed snapshot ID or wait for the pending work to finish.
Tool errors
Section titled “Tool errors”Return a Go error when the tool cannot safely produce a meaningful result:
func lookupOrder(ctx *ai.ToolContext, input LookupOrderInput) (LookupOrderOutput, error) { order, err := db.LookupOrder(ctx, input.OrderID) if err != nil { // The lookup itself failed (e.g. the database is unreachable); this is // a tool failure, distinct from a found-but-empty result below. return LookupOrderOutput{}, fmt.Errorf("look up order %q: %w", input.OrderID, err) } if order == nil { return LookupOrderOutput{}, core.NewError(core.NOT_FOUND, "order %q not found", input.OrderID) } return LookupOrderOutput{OK: true, Order: order}, nil}Return structured output when the model should recover:
if order == nil { return LookupOrderOutput{ OK: false, Reason: "ORDER_NOT_FOUND", Message: "Ask the user to check the order ID.", }, nil}Transform failures
Section titled “Transform failures”State and stream transforms fail closed. If a transform returns an error, the read or invocation fails instead of exposing unredacted data. Use this behavior for authorization-dependent redaction where returning raw state would leak sensitive information.