5.3 Error Handling in Agent Flows

Key Takeaways

  • Design explicit error-handling patterns in agent flows—scopes with run-after (try/catch style), retries for transient faults, and controlled terminate paths—so the agent always receives a usable response contract.
  • Respond to the agent with structured success/failure outputs and user-facing messages; never leak raw stack traces or secrets into chat.
  • Know major flow-related agent error codes: FlowActionBadRequest, FlowActionException, FlowActionTimedOut, BindingKeyNotFoundError, and capacity/auth related failures.
  • Use Configure run after for Failed/Timed out/Skipped paths; apply retry policies (fixed or exponential) only where retries are safe and idempotent.
  • Think dead-letter style for agents: capture failed context (correlation id, inputs summary, error code), notify owners or queues, and offer user fallback or human handoff instead of silent failure.
Last updated: August 2026

5.3 Error Handling in Agent Flows

Quick Answer: Wrap risky connector work in a Try scope; add a Catch scope that runs after the Try scope fails (and often after timed out). Use retry policies for transient HTTP/connector faults. Always Respond to the agent with structured outputs (Succeeded, UserMessage, optional ErrorCode). Log failures for operators (dead-letter thinking). Map agent error codes to fixes: bad request/schema, missing outputs, 100-second timeout, capacity, and auth.

Microsoft’s integration guidance is blunt: the developer must design an error-handling pattern so the agent knows how to handle exceptions. Agent flows will not magically convert every connector failure into a graceful chat reply. AB-620 rewards designs that fail loudly to operators and politely to users.

Why agent flows need deliberate resilience

Agent flows call external systems under conversational time pressure. Failures include:

  • Transient network blips and HTTP 429/5xx throttling
  • Business validation errors (HTTP 400/422)
  • Auth failures (401/403, expired connections, maker connection blocked)
  • Timeouts when logic exceeds the agent’s ~100-second wait
  • Schema/binding mistakes at the agent boundary
  • DLP or capacity enforcement

Without handling, users see generic errors, makers lack correlation data, and retries may double-submit orders. Resilience design prevents all three.

Error-handling building blocks

1) Scopes and try/catch (run after)

Group related actions into a Scope (commonly named Try). Create a second Scope (Catch) and set Configure run after so Catch runs when Try has failed (and, if appropriate, has timed out). Optionally add a Finally-style scope that runs after both success and failure for cleanup logging.

ScopeRun afterResponsibility
TryDefault (success path of previous)Happy-path connectors and transforms
CatchTry Failed / Timed outBuild user-safe message, set Succeeded=false, notify ops, write failure row
Success respondTry SucceededMap results; Respond to the agent with success outputs
Failure respondCatch completedRespond to the agent with failure outputs (if not already responded)

Critical rule: On both success and failure paths that the agent is waiting on, ensure Respond to the agent still runs with a complete output schema. An uncaught failure that skips Respond produces FlowActionException (no output / missing output).

2) Configure run after on individual actions

For finer control, set run-after on a single action:

  • Is successful — default chain
  • Has failed — compensation or alternate connector
  • Is skipped — branch when a condition skipped upstream
  • Has timed out — slow system fallback

Example: if “Create ServiceNow incident” fails, run-after Failed sends a Teams message to the service desk queue and Responds to the agent with a handoff message.

3) Retry policies

On connector/HTTP actions, configure Retry policy in settings:

Policy ideaUse whenAvoid when
NoneBusiness errors that will not self-heal
Fixed intervalSimple transient blipsLong agent wait budget already tight
ExponentialThrottling (429) and intermittent 5xxNon-idempotent create without dedupe keys

Retries help transient faults. They hurt when the action is a non-idempotent “create payment” without an idempotency key—you may create duplicates. Prefer retries on read and safe update operations; for creates, use connector upsert patterns or store a client-generated idempotency key.

Respect overall agent timeout: aggressive retries inside the pre-respond path can cause FlowActionTimedOut even if the eventual call would succeed.

4) Terminate and controlled stop

Use Terminate (or equivalent control) in deep automation branches that should not continue after a fatal configuration error—but if the agent is still waiting, Respond first with failure outputs, then terminate remaining work. Terminating without responding leaves the agent hanging until timeout.

5) Conditions as guard rails

Before expensive calls:

  • If OrderId is empty → Respond (Succeeded=false, clear UserMessage)
  • Else → continue into the Try scope with the connector call

Guard rails are cheaper than catch blocks after a failed API call.

Agent-facing error contract (user messages)

Separate three channels of information:

ChannelAudienceContent
UserMessage outputEnd userShort, polite, actionable (“I couldn’t create the ticket. Try again or ask for an agent.”)
ErrorCode outputTopic logic / supportStable code (CRM_TIMEOUT, VALIDATION)
Ops payloadMakers/adminsCorrelation id, action name, raw connector message in logs—not in chat

Never return secrets, tokens, connection strings, or full exception stacks to the user channel. Pair flow failures with topic On Error / fallback messaging so channel UX stays professional even when orchestration surfaces platform codes.

Sample structured outputs

OutputSuccess exampleFailure example
Succeededtruefalse
UserMessage“Incident INC012345 was created.”“I couldn’t reach ServiceNow. A human can help if you retry or ask for support.”
RecordIdINC012345null or empty
ErrorCodeOKSNOW_HTTP503
CorrelationIdguidsame guid used in ops log

Topics can branch on Succeeded to show Adaptive Cards vs escalate.

Dead-letter style thinking for agents

Classic integration uses a dead-letter queue for messages that cannot be processed. Agent solutions need the same idea even when the transport is a conversation:

  1. Capture — write failed run metadata to Dataverse, SharePoint list, or Log Analytics (who, when, inputs summary, error, correlation id).
  2. Notify — Teams/email to the owning queue when failure rate spikes or high-severity actions fail.
  3. Preserve user progress — tell the user what was not done; avoid implying a ticket exists when create failed.
  4. Offer recovery — retry guidance, alternate topic, or human-in-the-loop / handoff.
  5. Do not poison the user — one failure should not loop infinitely (InfiniteLoopInBotContent risk if topics re-call a failing flow without backoff).

This is “dead-letter thinking”: failed work is recorded and owned, not dropped on the floor when the chat session ends.

Platform error codes makers must map

Error / signalTypical causeFirst fix
FlowActionBadRequestMalformed call; type mismatch; missing input; unsupported parameter typeAlign types; supply required inputs; refresh bindings
FlowActionExceptionFlow error or missing outputs vs agent schemaFlow checker + run history; ensure Respond outputs
FlowActionTimedOutNo response within ~100 secondsOptimize queries; respond earlier; move work after Respond
BindingKeyNotFoundErrorInputs/outputs changed; stale bindingsRefresh/re-add flow on agent
FlowMakerConnectionBlockedMaker connection not allowed for runRun-only user connections / share flow with run-only permissions
ExecutionTimeout / HTTP 408/504Dependency too slowNarrow queries; retries with care; async post-respond work
HTTP 429 / QuotaExceededThrottling or capacityBackoff; reduce calls; capacity planning
DataLossPreventionViolationDLP / auth policyAlign connectors and authentication with admin policy
EnforcementMessageC2Usage limitPrepaid capacity or pay-as-you-go

When the agent surfaces these codes in test chat, pair them with Activity map + flow run history as taught in 5.1.

End-to-end resilience pattern (reference architecture)

  1. Validate inputs (conditions) → early Respond on validation failure.
  2. Try scope: connector actions with retry on idempotent calls; timeouts tuned.
  3. On success: map fields → Respond to the agent (Succeeded=true, clean UserMessage).
  4. Catch scope (run after failed/timed out): compose UserMessage + ErrorCode → write dead-letter row → notify ops → Respond to the agent (Succeeded=false).
  5. After respond (optional): non-blocking analytics, secondary notifications.
  6. Agent topic: if Succeeded is false, offer retry once, then escalate to human.
  7. Monitor: Activity failed filter + weekly review of dead-letter table.

Scenario — Contoso refund flow

Contoso’s agent can request refunds under $50 automatically and larger amounts with approval. Error handling:

  • Validation catch: amount missing → user message, no ERP call.
  • ERP create with exponential retry for 429 only; idempotency key = conversation id + refund request id.
  • If ERP fails after retries: Catch responds Succeeded=false, logs row, posts to Finance Teams channel with correlation id.
  • If amount > 50: human-in-the-loop approval; if approver rejects, Respond with clear denial message—not an exception.
  • Timeout risk: ERP status poll moved after Respond once the refund id exists, so the agent is not blocked.

Scenario — Schema mismatch in production

A maker adds required output ApprovalStatus but forgets to refresh the agent. Users see FlowActionException. Fix is not “more retries”—retries cannot invent a missing schema binding. Refresh tool bindings and republish; add a CI checklist item for schema changes.

Testing error paths (non-negotiable)

Happy-path designer tests are insufficient. Before production:

  1. Force connector failure (invalid id) and confirm Catch Respond outputs.
  2. Force timeout (mock delay) and confirm user message + ops log.
  3. Call with missing required input from the agent tool.
  4. Verify retries do not create duplicate records.
  5. Confirm Activity shows Failed vs Complete appropriately and that transcripts remain understandable.
  6. Retest after each parameter rename.

Exam decision table

SymptomBest design response
Occasional 503 from LOB APIRetry policy + Catch fallback message
Invalid user inputGuard condition + Respond without calling LOB
Flow exceeds 100sRespond earlier; continue work after Respond
Duplicate orders on retryIdempotency key / disable blind retries on create
Users see raw errorsUserMessage contract + topic fallback
Failures invisible to opsDead-letter log + notification
Errors after parameter renameRefresh agent bindings, not only flow retries

Resilience checklist for AB-620

  1. Try/Catch scopes with correct run after settings.
  2. Retry only where safe; document idempotency.
  3. Respond on every agent-waited path with full output schema.
  4. User-safe messages; operator-rich logs.
  5. Time budget awareness for the 100-second rule.
  6. Dead-letter or equivalent failure capture.
  7. Mapped understanding of FlowAction* and binding errors.
  8. Channel retests after publishing fixes.

Error handling is how agent flows earn trust. On AB-620, choose patterns that keep the agent informed, the user calm, and the operator informed—using scopes, run-after, retries, terminate discipline, and structured Respond outputs as your standard resilience toolkit.

Test Your Knowledge

You want a Catch path to run when any action inside a Try scope fails. Which configuration implements that try/catch pattern in an agent flow?

A
B
C
D
Test Your Knowledge

An agent flow must call a non-idempotent “create order” API. Which error-handling choice is safest?

A
B
C
D
Test Your Knowledge

Users receive FlowActionTimedOut when an agent calls a flow that eventually succeeds after three minutes. What is the best remediation?

A
B
C
D