DEV Community

Cover image for Exception Handling in Power Automate
david wyatt
david wyatt

Posted on • Updated on

Exception Handling in Power Automate

Exception handling is key to all automations, as no matter how hard we try there will always be unexpected behaviour

The run after isn't the most intuitive exception handling I've seen (Blue Prism does it better), but once you used it a few times it's not too bad.

How To

Exception handling is configure in the run after setting. As good practice I recommend in most cases you should catch fails and timeouts.

run after

Parallel branches can be used to divert and handle exceptions, with either the branch ending the flow or rejoining after handling the exception.
Scopes are key to exception handling, as they create a block that can be handled the same i.e if ay action fails within the Scope it will trigger the exception handling. Additionally wrapping all your exception actions within its own Scope ensures all those actions run.

error logic

The exception detail can be found and used with the following 2 expressions

actions() - For action exception
result() - For container (e.g scope/condition/loop)

No just to makes things more interesting I have (so far) found 3 different exception schemas, so for The actions() we have::

Type 1

{
  "name": "Compose",
  "startTime": "2023-11-28T11:24:54.1360838Z",
  "endTime": "2023-11-28T11:24:54.1368194Z",
  "trackingId": "238f1d13-aafc-4aaf-ad64-35123f51011b",
  "clientTrackingId": "08585004363290835095277375624CU45",
  "clientKeywords": [
    "testFlow"
  ],
  "code": "BadRequest",
  "status": "Failed",
  "error": {
    "code": "InvalidTemplate",
    "message": "Unable to process template language expressions in action 'Compose' inputs at line '0' and column '0': 'The template language function 'int' was invoked with a parameter that is not valid. The value cannot be converted to the target type.'."
  }
}
Enter fullscreen mode Exit fullscreen mode

Type 2

{
  "name": "HTTP",
  "inputs": {
    "host": {
      "apiId": "subscriptions/72c9792d-e7e6-4eb5-b764-fc599b9b3005/providers/Microsoft.Web/locations/westus/runtimes/unitedstates-002/apis/sharepointonline",
      "connectionReferenceName": "shared_sharepointonline",
      "operationId": "HttpRequest"
    },
    "parameters": {
      "dataset": "https://sharepoint.com/sites/",
      "parameters/method": "GET",
      "parameters/uri": "_api/test?excpetion=true"
    }
  },
  "outputs": {
    "statusCode": 404,
    "headers": {
      "Cache-Control": "no-store, no-cache",
      "Pragma": "no-cache",
      "Set-Cookie": "ARRAffinity=40237ffdc57de1390eeff374e782e979bae0af189a51754a0bc4cff0e861cdf3;Path=/;HttpOnly;Secure;Domain=sharepointonline-scus.azconn-scus-001.p.azurewebsites.net,ARRAffinitySameSite=40237ffdc57de1390eeff374e782e979bae0af189a51754a0bc4cff0e861cdf3;Path=/;HttpOnly;SameSite=None;Secure;Domain=sharepointonline-scus.azconn-scus-001.p.azurewebsites.net",
      "Strict-Transport-Security": "max-age=31536000; includeSubDomains",
      "x-ms-request-id": "f77df2a0-30c5-4000-719f-851232ca50c8",
      "X-Content-Type-Options": "nosniff",
      "X-Frame-Options": "DENY",
      "Timing-Allow-Origin": "*",
      "x-ms-apihub-cached-response": "false",
      "x-ms-apihub-obo": "false",
      "Date": "Tue, 28 Nov 2023 11:31:17 GMT",
      "Content-Length": "383",
      "Content-Type": "application/json",
      "Expires": "-1"
    },
    "body": {
      "status": 404,
      "message": "Cannot find resource for the request test.\r\nclientRequestId: 5ff1e5-26f1-4224-99e7-cbe1c1837b1a\r\nserviceRequestId: f77df2a0-30c5-4000-719f-851232ca50c8",
      "source": "https://sharepoint.com/sites//_api/test?excpetion=true",
      "errors": [
        "-1",
        "Microsoft.SharePoint.Client.ResourceNotFoundException"
      ]
    }
  },
  "startTime": "2023-11-28T11:31:18.0648326Z",
  "endTime": "2023-11-28T11:31:18.4852347Z",
  "trackingId": "2d78395c-461e-4768-8035-5649039455a1",
  "clientTrackingId": "08585004358075242826545384959CU152",
  "clientKeywords": [
    "testFlow"
  ],
  "code": "NotFound",
  "status": "Failed"
}
Enter fullscreen mode Exit fullscreen mode

Type 3

{
  "name": "HTTP",
  "inputs": {
    "host": {
      "apiId": "subscriptions/72c9792d-e7e6-4eb5-b764-fc599b9b3005/providers/Microsoft.Web/locations/westus/runtimes/unitedstates-002/apis/sharepointonline",
      "connectionReferenceName": "shared_sharepointonline",
      "operationId": "HttpRequest"
    },
    "parameters": {
      "dataset": "https://sharepoint.com/sites/",
      "parameters/method": "GET",
      "parameters/uri": "_api/test?excpetion=true"
    }
  },
  "outputs": {
    "statusCode": 404,
    "headers": {
      "Cache-Control": "no-store, no-cache",
      "Pragma": "no-cache",
      "Set-Cookie": "ARRAffinity=40237ffdc57de1390eeff374e782e979bae0af189a51754a0bc4cff0e861cdf3;Path=/;HttpOnly;Secure;Domain=sharepointonline-scus.azconn-scus-001.p.azurewebsites.net,ARRAffinitySameSite=40237ffdc57de1390eeff374e782e979bae0af189a51754a0bc4cff0e861cdf3;Path=/;HttpOnly;SameSite=None;Secure;Domain=sharepointonline-scus.azconn-scus-001.p.azurewebsites.net",
      "Strict-Transport-Security": "max-age=31536000; includeSubDomains",
      "x-ms-request-id": "f77df2a0-30c5-4000-719f-851232ca50c8",
      "X-Content-Type-Options": "nosniff",
      "X-Frame-Options": "DENY",
      "Timing-Allow-Origin": "*",
      "x-ms-apihub-cached-response": "false",
      "x-ms-apihub-obo": "false",
      "Date": "Tue, 28 Nov 2023 11:31:17 GMT",
      "Content-Length": "383",
      "Content-Type": "application/json",
      "Expires": "-1"
    },
    "body": {
      "status": 404,
      "message": "Cannot find resource for the request test.\r\nclientRequestId: 5ff1e5-26f1-4224-99e7-cbe1c1837b1a\r\nserviceRequestId: f77df2a0-30c5-4000-719f-851232ca50c8",
      "source": "https://sharepoint.com/sites//_api/test?excpetion=true",
      "errors": [
        "-1",
        "Microsoft.SharePoint.Client.ResourceNotFoundException"
      ]
    }
  },
  "startTime": "2023-11-28T11:31:18.0648326Z",
  "endTime": "2023-11-28T11:31:18.4852347Z",
  "trackingId": "2d78395c-461e-4768-8035-5649039455a1",
  "clientTrackingId": "08585004358075242826545384959CU152",
  "clientKeywords": [
    "testFlow"
  ],
  "code": "NotFound",
  "status": "Failed"
}
Enter fullscreen mode Exit fullscreen mode
  • Type 1: error.message (e.g compose, Outlook Send Email)
  • Type 2: outputs.body.message (e.g SharePoint HTTP, Get Items)
  • Type 3: outputs.body.error.innerError.message (e.g Create Item)

So you will need to target the expression to the right action type

actions('nameOfActionString')?['error']?['message']
actions('nameOfActionString')?['outputs']?['body']?['message']
actions('nameOfActionString')?['outputs']?['body']?['error']?['innerError']?['message']

Enter fullscreen mode Exit fullscreen mode

But as I said recommend result() as catching exceptions from Scopesis easier. It returns the exact same objects but in an array instead. But with two caveats, this only works on the Scope/Condition level (so a condition within a scope wont work), Loops are a little different.

So Type 1 would now look like this (wrapped in an array):

[
  {
    "name": "Compose",
    "startTime": "2023-11-28T11:35:25.4082007Z",
    "endTime": "2023-11-28T11:35:25.4090563Z",
    "trackingId": "3ed89fb2-63f7-45c1-9954-60c2bc9b17de",
    "clientTrackingId": "08585004358075242826545384959CU152",
    "clientKeywords": [
      "testFlow"
    ],
    "code": "BadRequest",
    "status": "Failed",
    "error": {
      "code": "InvalidTemplate",
      "message": "Unable to process template language expressions in action 'Compose' inputs at line '0' and column '0': 'The template language function 'int' was invoked with a parameter that is not valid. The value cannot be converted to the target type.'."
    }
  }
]
Enter fullscreen mode Exit fullscreen mode

Because loops add anther dimension there is an additional 'outputs' array, which is for each iteration of the loop, so Type 1 now looks like:

[
  {
    "name": "Compose",
    "outputs": [
      {
        "name": "Compose",
        "startTime": "2023-11-28T11:58:57.5417291Z",
        "endTime": "2023-11-28T11:58:57.5431434Z",
        "trackingId": "17760050-59f1-46ae-b9c7-cabfb4edcb46",
        "clientTrackingId": "08585004358075242826545384959CU152",
        "clientKeywords": [
          "testFlow"
        ],
        "code": "BadRequest",
        "status": "Failed",
        "error": {
          "code": "InvalidTemplate",
          "message": "Unable to process template language expressions in action 'Compose' inputs at line '0' and column '0': 'The template language function 'int' was invoked with a parameter that is not valid. The value cannot be converted to the target type.'."
        }
      },
      {
        "name": "Compose",
        "startTime": "2023-11-28T11:58:57.752149Z",
        "endTime": "2023-11-28T11:58:57.7531706Z",
        "trackingId": "e870f823-3e34-4d4a-9df8-f97ad69f5b2d",
        "clientTrackingId": "08585004358075242826545384959CU152",
        "clientKeywords": [
          "testFlow"
        ],
        "code": "BadRequest",
        "status": "Failed",
        "error": {
          "code": "InvalidTemplate",
          "message": "Unable to process template language expressions in action 'Compose' inputs at line '0' and column '0': 'The template language function 'int' was invoked with a parameter that is not valid. The value cannot be converted to the target type.'."
        }
      }
    ],
    "startTime": "2023-11-28T11:58:58.1446105Z",
    "endTime": "2023-11-28T11:58:58.1452165Z",
    "trackingId": "4f95aaa2-a00f-4748-bce0-3b6ba566b138",
    "clientTrackingId": "08585004358075242826545384959CU152",
    "clientKeywords": [
      "testFlow"
    ],
    "code": "NotSpecified",
    "status": "Failed",
    "repetitionCount": 2
  }
]
Enter fullscreen mode Exit fullscreen mode

You have 2 options with result(), either filter and return all failed as a table (HTML/Markdown table to display it nicely), or you can just grab the first from the filter if you flow is likely to only fail in one place.

So no matter what this is going to be a little challenging, but heres my recommendations:

Use a top level scope and catch the first error from the result. I do this because I can use one expression (will show you below) to catch all, and because I build my flows with minimum nesting. If I have a loop inside my scoop I handle the excpetion inside (as dont want 1000's of messages). If there is a switch/condition that needs it I will add another exception catch just for that container.

So whats the clever expression, well its

coalesce(
    sort(result('Main'),'status')[0]?['error']?['message']
,
     sort(result('Main'),'status')[0]?['outputs']?['body']?['message']
,
     sort(result('Main'),'status')[0]?['outputs']?['body']?['error']?['innerError']?['message']
)
Enter fullscreen mode Exit fullscreen mode

It uses the coalesce expression which uses the first non null value (so ignores the unused results) and I sort the result array, ensuring the first item is the 'failed' action.

exception handling


There are 3 different types/categories for exception handling

  • Process
  • Business
  • System

Process

Process exceptions are exception handling used as logic. So it's almost used as a condition, with the expectation the process will continue i.e. its not a real exception.

process flow except

These are generally called try, catch, continue, and although very useful I'm personally not a fan. I would rather try standard logic to check and then not try, rather then try and deal with the error.

Business

Business exceptions are exceptions generated by input data, and are generally in loops. What's key about them is we don't want to end the process, we just want to flag that item as exception, and continue with the other items.

business flow except

These generally only have one action, and may not need a Scope to contain them. Though to ensure the process continues the action after the loop would have to have run after Success and Failed enabled. A good example would be a to add a row to a SharePoint list, so that those items can be manually processed/corrected.

System

System exceptions are when something unexpected in the flow happens. Either a connector is failing due to the api or a key file can't be found. In these cases the process should carry out any clean up actions (e.g delete temp files) and escalate. This could be like a business exception with entry in a SharePoint list, but generally as its more serious I would recommend a teams message or email.

A good tip for system exceptions are:

Wrap the entire process in a Exception
Having a 'Main' Scope that contains every action means that a system exception after can catch any error in process. Although we mostly get failed emails from Power Automate, this is no good if running under a Service Account.

system flow except

Terminate after handling
Use the Terminate action set to fail, this allows you to still identify failed runs in the logs.

Run link
The below expression creates a link to the failed run, so if added to the message/email, the user can click the link and go straight to the faile run. An added bonus is these links work longer then the normal retention (last 100 runs, I've got a link over a 1000 runs previous) and it can be accessed by environment admins without sharing the flow.

concat('https://make.powerautomate.com/manage/environments/', workflow()?['tags']?['environmentName'], '/flows/', workflow()?['name'], '/runs/', workflow()?['run']['name'])

flow failed

Top comments (2)

Collapse
 
prusakpl profile image
Piotr Rusak

Hi @wyattdave,
What is your recommendation for Exception handling when exception happens inside Do-Until loop (this is the only exception in Power Automate where Exceptions are not bubbling outside of the loop).

Collapse
 
wyattdave profile image
david wyatt

I think of these as generally business exceptions as the item being processed is generating the exception. In these cases I recommend handling each individually so that the flow can continue with the successful items. I would then log the failed items in a list/array and handle them separately.