← Back to Tutorials
Intermediate⏱️ 30 min

Error Handling — Scopes, Try-Catch, and Retry Policies

Error Handling — Scopes, Try-Catch, and Retry Policies

Why Error Handling Matters in Production

In production workflows, failures are inevitable. External APIs go down, data formats change unexpectedly, and network timeouts occur. Without proper error handling, a single failed action can leave your workflow in an inconsistent state — data partially processed, downstream systems out of sync, and no visibility into what went wrong.

Robust error handling ensures:

  • Resilience: Workflows recover gracefully from transient failures
  • Observability: Teams are notified immediately when issues arise
  • Data integrity: Partial failures don't corrupt business data
  • Compliance: Audit trails capture failure details for regulatory requirements

Scope Action (Grouping Actions)

A Scope is a container action in Logic Apps that groups multiple actions together. Think of it as a logical block — similar to curly braces {} in programming languages.

Key characteristics:

  • Scopes can contain any number of actions, including nested scopes
  • A scope's status reflects the aggregate result of its child actions
  • If any child action fails, the scope itself is marked as Failed
  • Scopes enable structured error handling by providing a single point to check success or failure

Screenshot: Adding a Scope action in the Logic Apps designer

{
  "Try_Scope": {
    "type": "Scope",
    "actions": {
      "Get_Record": { "type": "ApiConnection", "inputs": { "..." } },
      "Transform_Data": { "type": "Compose", "inputs": { "..." } },
      "Update_Database": { "type": "ApiConnection", "inputs": { "..." } }
    }
  }
}

Try-Catch Pattern Using Scope + Run After Configuration

Logic Apps implements the Try-Catch pattern by combining Scopes with Run After configuration. This gives you the same structured error handling you'd find in traditional programming languages.

The pattern consists of:

  1. Try Scope — Contains the main business logic
  2. Catch Scope — Runs only when the Try Scope fails; handles the error
  3. Finally Scope — Runs regardless of outcome; performs cleanup

Screenshot: Try-Catch-Finally pattern in the designer

Run After Settings

Every action in Logic Apps can be configured with Run After settings that determine when it executes relative to the preceding action. The four statuses are:

StatusDescription
SucceededThe previous action completed successfully (default)
FailedThe previous action failed with an error
SkippedThe previous action was skipped (e.g., condition not met)
Timed OutThe previous action exceeded its timeout limit

You can select multiple statuses. For a Catch Scope, configure it to run after the Try Scope has Failed, Timed Out, or both.

Screenshot: Configuring Run After settings on the Catch scope

To configure Run After in the designer:

  1. Click the three dots (...) on the Catch Scope action
  2. Select Configure run after
  3. Check has failed and has timed out
  4. Uncheck is successful

Retry Policies

Retry policies handle transient failures automatically before escalating to your error handling logic. Logic Apps supports four retry policy types:

None

No retries. The action fails immediately on the first error.

"retryPolicy": {
  "type": "none"
}

Fixed Interval

Retries at a consistent interval between attempts.

"retryPolicy": {
  "type": "fixed",
  "count": 3,
  "interval": "PT30S"
}

Exponential Backoff

Increases the wait time between retries exponentially, reducing pressure on struggling services.

"retryPolicy": {
  "type": "exponential",
  "count": 4,
  "interval": "PT10S",
  "maximumInterval": "PT1H",
  "minimumInterval": "PT5S"
}

Custom

Define specific intervals for each retry attempt.

"retryPolicy": {
  "type": "custom",
  "count": 3,
  "intervals": ["PT10S", "PT30S", "PT1M"]
}

Screenshot: Configuring retry policy on an HTTP action

Step-by-Step: Build a Workflow with Try, Catch, and Finally Scopes

Step 1: Create the Try Scope

  1. Add a new Scope action and rename it to Try
  2. Inside the scope, add your business logic actions:
    • HTTP action to call an external API
    • Parse JSON to process the response
    • Insert Row to save data to a database

Screenshot: Try scope with business logic actions

Step 2: Create the Catch Scope

  1. After the Try scope, add another Scope and rename it to Catch
  2. Configure Run After on the Catch scope:
    • Uncheck is successful
    • Check has failed
    • Check has timed out
  3. Inside the Catch scope, add error handling actions:
    • Compose action to capture the error using result('Try') expression
    • Send an email or Post to Teams with error details
    • Optionally Insert Row to log the error to a tracking table

Screenshot: Catch scope with Run After configured for failure

Step 3: Create the Finally Scope

  1. After the Catch scope, add a third Scope and rename it to Finally
  2. Configure Run After on the Finally scope:
    • Check is successful
    • Check has failed
    • Check has skipped
    • Check has timed out
  3. Inside the Finally scope, add cleanup actions:
    • HTTP action to release locks or close connections
    • Compose action to log the final workflow status

Screenshot: Finally scope configured to run after all outcomes

Step 4: Test the Workflow

  1. Save and run the workflow with valid inputs — verify the Try scope succeeds and Finally runs
  2. Introduce a failure (e.g., invalid URL) — verify the Catch scope executes and Finally still runs
  3. Check that error notifications are received

Terminate Action

The Terminate action immediately ends the workflow run with a specified status:

  • Succeeded — Marks the run as successful
  • Failed — Marks the run as failed with an error code and message
  • Cancelled — Marks the run as cancelled

Use Terminate inside your Catch scope to explicitly mark the workflow as failed after handling the error:

{
  "Terminate_Failed": {
    "type": "Terminate",
    "inputs": {
      "runStatus": "Failed",
      "runError": {
        "code": "ExternalAPIFailure",
        "message": "The payment gateway API returned a 503 error after 3 retries."
      }
    }
  }
}

Screenshot: Terminate action configured with Failed status

Sending Error Notifications

Email Notifications (Office 365 Outlook)

Inside your Catch scope, add a Send an email (V2) action:

  • To: ops-team@contoso.com
  • Subject: Logic App Failed: @{workflow().name}
  • Body: Include the error details from result('Try')
Workflow: @{workflow().name}
Run ID: @{workflow().run.name}
Timestamp: @{utcNow()}
Error: @{result('Try')?[0]?['error']?['message']}

Microsoft Teams Notifications

Add a Post message in a chat or channel action:

  • Team: Operations
  • Channel: Alerts
  • Message: Format with Adaptive Card for rich error details

Screenshot: Teams notification with error details

Real-World Error Handling Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    Logic App Workflow                            │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ TRY SCOPE                                               │   │
│  │  ┌──────────┐   ┌──────────────┐   ┌───────────────┐   │   │
│  │  │ Call API │──▶│ Transform    │──▶│ Save to DB    │   │   │
│  │  │(Retry:3) │   │ Data         │   │               │   │   │
│  │  └──────────┘   └──────────────┘   └───────────────┘   │   │
│  └─────────────────────────────────────────────────────────┘   │
│                          │ Failed/Timed Out                      │
│                          ▼                                       │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ CATCH SCOPE (Run After: Failed, Timed Out)              │   │
│  │  ┌──────────┐   ┌──────────────┐   ┌───────────────┐   │   │
│  │  │ Capture  │──▶│ Log Error    │──▶│ Notify Team   │   │   │
│  │  │ Error    │   │ to Table     │   │ (Email/Teams) │   │   │
│  │  └──────────┘   └──────────────┘   └───────────────┘   │   │
│  │                                          │               │   │
│  │                                          ▼               │   │
│  │                                   ┌───────────────┐      │   │
│  │                                   │ Terminate     │      │   │
│  │                                   │ (Failed)      │      │   │
│  │                                   └───────────────┘      │   │
│  └─────────────────────────────────────────────────────────┘   │
│                          │ Always                                │
│                          ▼                                       │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ FINALLY SCOPE (Run After: All statuses)                 │   │
│  │  ┌──────────────┐   ┌──────────────────────────────┐    │   │
│  │  │ Release      │──▶│ Log Final Status             │    │   │
│  │  │ Resources    │   │                              │    │   │
│  │  └──────────────┘   └──────────────────────────────┘    │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

Screenshot: Complete error handling architecture in the designer


← Previous: Variables and Loops | Next: Calling APIs →