Skip to content
CloudOps
Newsletter
All guides
AI for Microsoft Teams By James Joyner IV · · 11 min read

Power Automate Error Handling: Retries and Try-Catch Scopes

Flows fail silently and you find out from an angry channel. Learn run-after configs, retry policies, and Scope-based try-catch to make Teams flows resilient.

  • #microsoft-teams
  • #power-automate
  • #error-handling
  • #resilience
  • #devops

My first real Power Automate flow posted CI/CD results into a Teams channel. It worked beautifully until the day our internal API hiccupped, the HTTP action failed, and the flow just stopped. No card, no error in the channel, no notification to me. I found out three hours later when someone asked why deploys had “gone quiet.” A flow that fails silently is worse than no flow, because people stop watching the channel manually and trust the automation that has quietly died.

This guide is about making Power Automate flows fail loudly and recover automatically. We will cover run-after configuration, action-level retry policies, and the Scope-based try-catch-finally pattern. I prototype flow logic with an AI assistant because describing “retry three times then post to the dead-letter channel” in English and getting a starting structure back is genuinely faster. But the model is a fast junior engineer: it produces a happy-path flow and forgets the failure path entirely unless you push it. A human reviews the error handling before this runs against a real tenant, and you never paste live connector credentials into a prompt.

Run-after: the foundation of flow error handling

Every action in a flow has a “configure run after” setting that decides when it executes based on the previous action’s result: is successful, has failed, is skipped, or has timed out. By default actions only run after success, which is why a failed HTTP action halts everything downstream.

The try-catch pattern is built entirely on run-after. You put your risky actions in one Scope, then add a second Scope configured to run only after the first has failed, is skipped, or has timed out. That second Scope is your catch block.

In the flow’s underlying JSON (visible via the code view or when exporting), run-after looks like this:

"Catch_Scope": {
  "type": "Scope",
  "runAfter": {
    "Try_Scope": ["Failed", "Skipped", "TimedOut"]
  },
  "actions": { /* notify dead-letter channel, log, etc. */ }
}

The three statuses together matter. If you only catch Failed, a TimedOut action slips past your catch block and the flow ends in an unhandled state.

Action-level retry policies

Before you even reach a catch block, many transient failures resolve themselves on retry. Each action in Power Automate has a retry policy setting. The default for most connectors is an exponential policy of four retries, but you can and should tune it for flaky internal endpoints.

"HTTP_Call_Internal_API": {
  "type": "Http",
  "inputs": {
    "method": "POST",
    "uri": "https://internal.example.com/deploy-status",
    "retryPolicy": {
      "type": "exponential",
      "count": 4,
      "interval": "PT10S",
      "maximumInterval": "PT1M"
    }
  }
}

This retries four times with exponential backoff starting at ten seconds and capping at one minute. For a 429 or a 503 from a busy internal API, this alone fixes most failures before any human is involved. Set "type": "none" only when retrying would cause duplicates — like posting a Teams message — and you have not made the operation idempotent.

Pro Tip: Retry policies only kick in for retriable status codes — 408, 429, and 5xx. A 400 or 401 fails immediately, no retries, because retrying a malformed or unauthorized request just wastes time. If your “transient” failures are 401s, the problem is your auth token, not your retry count.

The full try-catch-finally shape

A robust flow has three Scopes:

  1. Try — the real work: call the API, build the Adaptive Card, post to Teams.
  2. Catch — runs after Try fails/skips/times out: capture the error, post to a dead-letter channel, optionally open an incident.
  3. Finally — runs regardless (configure run-after to include all four statuses on both Try and Catch): emit a metric, clean up.

Inside the Catch scope, the result() expression is gold. It returns the outcome of every action in a named scope so you can extract the actual error:

@{result('Try_Scope')}

Filter that array for the action whose status is Failed and read its error.message. Post that into your dead-letter channel as an Adaptive Card so the on-call engineer sees exactly which step blew up and why, not just “a flow failed.”

{
  "type": "TextBlock",
  "text": "Flow failed at: ${failedAction}",
  "weight": "Bolder",
  "color": "Attention",
  "wrap": true
}

Make the catch block actionable, not just noisy

A dead-letter message nobody can act on is just more noise. Include the run URL, the failed action name, the error message, and — if the operation is safe to repeat — an Action.Submit button that re-triggers the flow with the same inputs. That turns a 3am failure into a one-tap recovery instead of a manual archaeology session through run history.

For triage-heavy flows, I route the dead-letter channel through the same logic our incident-response dashboard uses, so a failed flow can escalate the same way a real alert does. The classification of “is this retriable or a real incident” is something I let AI suggest but a human confirms.

Where AI helps and where it must not decide alone

Describing the failure path in English and getting Scope JSON back is a real time-saver. I sketch the try-catch-finally shape with Claude or inside Cursor when editing exported flow definitions, then refine in the prompt workspace. The structured starters in my prompt packs get you past the blank-canvas stage. But the model does not know which operations are idempotent in your environment, so the decision to enable or disable retries on a side-effecting action is a human one. Review it, do not delegate it.

Conclusion

Silent flow failures erode trust faster than no automation at all. Build resilience in layers: tune retry policies for transient errors, wrap risky work in a Try scope, catch Failed/Skipped/TimedOut into an actionable dead-letter card, and use a Finally scope for cleanup. Let AI scaffold the structure, but own the idempotency and escalation decisions yourself, and keep tenant credentials out of every prompt. More Power Automate patterns are in the Microsoft Teams category.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.