Power Automate error handling patterns

How to handle errors robustly in Power Automate flows — try/catch scopes, configure run-after, retry policies, dead-letter handling, and the patterns that prevent silent failures.

Updated 2027-03-27

A Power Automate flow without error handling fails silently — the run shows red, but unless someone watches the run history, nobody notices. Robust flows handle errors explicitly: retry transient issues, route persistent failures to alerting, log context for debugging, and recover gracefully. The patterns aren't complex but they're not obvious to first-time makers.

The try/catch/finally pattern.

Power Automate's flow design doesn't have native try/catch syntax, but the equivalent is achieved through Scope actions plus the Configure Run After option:

  1. Wrap the main logic in a Scope action — labeled "Try" by convention.
  2. Add another Scope after — labeled "Catch".
  3. On the Catch scope, configure Run After = "has failed", "is skipped", or "has timed out" of the Try scope.
  4. Optionally add a third Scope labeled "Finally" — Run After = "is successful", "has failed", "is skipped", "has timed out" of both Try and Catch.

The flow structure:

Try (Scope) {
  ... main logic
}

Catch (Scope) - Run After "has failed" of Try {
  ... error logging, alerting, compensation
}

Finally (Scope) - Run After all of Try and Catch {
  ... cleanup, regardless of outcome
}

If anything in Try fails, the Try scope fails, Catch runs. If everything in Try succeeds, Catch is skipped, Finally still runs.

What to do in Catch.

  • Log the error. Inside the Catch, retrieve the failed action's output via actionOutputs('ActionName') or the workflow's overall error via result('Try'). Write to a Dataverse log table, Application Insights, or a notification channel.
  • Notify. Send a Teams message, email, or alert to operations. Critical failures go to a real distribution list; routine failures might just log.
  • Compensate. If the failed action had side effects, undo them. If you created a record then a downstream step failed, delete the record.
  • Decide whether to terminate the flow. Sometimes you log and continue (graceful degradation); sometimes you halt.

Retry policies.

Each action has a retry policy configurable via the action's settings:

  • None — fail immediately on error.
  • Default (exponential) — retry up to 4 times with exponential backoff. Used for transient failures.
  • Fixed — retry on a fixed schedule.
  • Exponential (configurable) — custom backoff.

Default retry handles transient HTTP 5xx errors, brief connector outages, throttling. Don't apply retry to non-idempotent operations — a "create record" action retrying could create duplicates.

Configure Run After granularity.

Beyond "has failed", Run After supports specific failure conditions:

  • is successful — only if the previous action succeeded.
  • has failed — only on failure.
  • is skipped — when the previous action was skipped (e.g. by a parent failure cascade).
  • has timed out — specifically when an action exceeded its timeout.

Combinations cover specific recovery scenarios — "retry on timeout but not on auth failure", for example.

Try/Catch within loops.

For Apply to Each loops:

  • Default behaviour: a single iteration's failure aborts the loop.
  • Continue on error: wrap the loop body in a Try/Catch scope; the Catch logs the failure but doesn't halt the loop. The loop processes remaining items.

This pattern is essential for bulk processing where one failure shouldn't block the rest.

Dead-letter handling.

For integrations that can't tolerate event loss, a dead-letter pattern:

  1. Try the main logic.
  2. On persistent failure (after retries exhausted), write the failed item to a "dead letter" table or queue.
  3. Operations team monitors the dead-letter table; investigates and reprocesses.

This handles the genuine "we couldn't do it now, but it must be done eventually" pattern.

Idempotency.

Retry-friendly flows must be idempotent — running the same action twice produces the same result. Patterns:

  • Check before create — query for the target record; create only if it doesn't exist.
  • Upsert — use the Dataverse "Upsert" pattern (insert if not exists, update if exists).
  • Correlation IDs — track each processing attempt; the downstream system uses the ID to detect duplicates.

Non-idempotent flows that retry create duplicate records, double-charge, or send multiple notifications.

Monitoring and alerting.

  • Run history — visible in the Power Automate maker portal. Manual review.
  • Application Insights — flows can write to App Insights via the HTTP action; centralised monitoring.
  • Failure notification flows — a "watcher" flow that scans recent failures and sends consolidated alerts.
  • CoE Starter Kit — surfaces flow failures across the tenant in dashboards.

Common pitfalls.

  • No error handling at all — flows fail silently.
  • Catch that doesn't log enough — alert says "flow failed" without context.
  • Retry without idempotency — duplicates pile up.
  • Continue on error globally — important failures are silently swallowed.
  • Try/Catch around trivial actions — the overhead exceeds the benefit.

Operational reality. Error handling is not optional for production flows. Build it from the start; revisit when failures surface. Failed flows that no one notices undermine confidence in the whole platform.

Related guides