Microsoft Flow Error Handling

Published on Author Rob Windsor4 Comments

If you search for information on Flow error handling you’ll find that the Flow community generally recommends using a pattern like the one shown below. The actions that implement the main body of the Flow go into a Scope which is followed by two parallel Scopes, one to hold the actions that complete a successful run and one to hold the actions for a run that failed or timed out.

 

Basic error handling pattern

 

Basic error handling pattern 2

 

If you are not familiar with Scopes, their main purpose is to act as a container for one or more actions. One of the benefits of using Scopes is that you can collapse them enabling you to get a big picture view of your Flow without having to scroll all over the place. However in this case we are also using the Scopes to clearly show both the success and failure paths for the Flow.

I’ve used the pattern shown above in several of the Flows I’ve built but I have always had one issue. If I was inside the Fail or Timeout Scope I knew something went wrong, but I didn’t think there was a way to determine exactly what that was. This issue bugged me so much that I kept searching until I finally found some Logic Apps documentation that discussed the @result() expression. Flow is built on top of Logic Apps so most things that apply to Logic Apps also apply to Flow.

The @result() expression accepts the name of a Scope as a parameter and returns a JSON array of objects that represent the results of the execution of each action within the Scope. The schema of the objects returned will vary depending on the type of action but all objects will have some common properties. The properties that are of interest in terms of error handling are: name, code and status.

The name property value is the name of the action, the code property value is a very terse description of the error, and the status property value indicates whether the action succeeded, failed, timed out, or was skipped.

Below are a couple example objects for actions that failed. You can see they both have the terse error description in the code property but they also have more detailed error information in other properties (note the error message in the second example was truncated for inclusion in this post). The issue is that the paths to the properties that contain the detailed error information are different in the two objects. It’s definitely possible to extract the detailed error information, you would just add a series of conditions that check for the existence of the different properties that could potentially hold it. However in this blog post we are going to keep things simple and just focus on how we can extract the error information that is common to all objects representing an action.

{
   "name": "Example_Action_That_Failed",
   "inputs": {
      "uri": "https://myfailedaction.azurewebsites.net",
      "method": "POST"
   },
   "outputs": {
      "statusCode": 404,
      "headers": {
         "Date": "Thu, 11 Aug 2016 03:18:18 GMT",
         "Server": "Microsoft-IIS/8.0",
         "X-Powered-By": "ASP.NET",
         "Content-Length": "68",
         "Content-Type": "application/json"
      },
      "body": {
         "code": "ResourceNotFound",
         "message": "/docs/folder-name/resource-name does not exist"
      }
   },
   "startTime": "2016-08-11T03:18:19.7755341Z",
   "endTime": "2016-08-11T03:18:20.2598835Z",
   "trackingId": "bdd82e28-ba2c-4160-a700-e3a8f1a38e22",
   "clientTrackingId": "08587307213861835591296330354",
   "code": "NotFound",
   "status": "Failed"
}

 

{
    "name": "Set_variable_2",
    "startTime": "2019-04-15T22:12:02.1199356Z",
    "endTime": "2019-04-15T22:12:02.1199356Z",
    "trackingId": "7fdf54a0-ab29-4087-affd-319864513ed9",
    "clientTrackingId": "08586462405637382345452520112CU22",
    "clientKeywords": [
        "testFlow"
    ],
    "code": "BadRequest",
    "status": "Failed",
    "error": {
        "code": "InvalidTemplate",
        "message": "Unable to process template language expressions ..."
    }
}

We’ll start by adding an Initialize variable action above the Main Scope. This action will initialize a String variable named ErrorDetails to an empty string.

Initialize ErrorDetails variable

Then inside the Fail or Timeout Scope, add a Filter array action. We will use this action to get the details of the actions inside the Main Scope that either failed or timed out. To do this we’ll set the the From property value (marked as 1 in the screen capture) to the expression result(‘Main’), we’ll set the left-hand side of the filter condition (marked as 2 in the screen capture) to the expression: createArray(‘Failed’, ‘TimedOut’), and we’ll set the right-hand side of the filter condition (marked as 3 in the screen capture) to the expression item()[‘status’].

Filter results of Main Scope

Add an Apply to each action below the Filter array action. This action should iterate over the output of the Filter array action. In most cases the output array will only contain a single object but it is possible that it could contain multiple objects.

Apply to each result

Add an Append to string variable action inside the Apply to each action. Will use this action to append the the error information for the current result to the ErrorDetails string variable. The expression marked as 1 injects the value of the name property: items(‘Apply_to_each_result’)[‘name’]. The expression marked as 2 injects the value of the status property: items(‘Apply_to_each_result’)[‘status’]. The expression marked as 3 injects the value of the code property: items(‘Apply_to_each_result’)[‘code’].

Append error details for current action

Add a Send an email action below the Apply to each action. We’ll use this action to notify one or more users that the Flow failed or timed out. Set the To property to the user(s) you wish to notify, set the Subject property to something appropriate for your situation, and set the Importance property to High.

In the Body, start by adding the ErrorDetails variable value. Then we’ll add a link that the Flow owners can click to see the run history for the Flow. I got the expression to build the link from the Try, Catch and Finally Flow template: concat(‘https://flow.microsoft.com/manage/environments/’,
workflow()?[‘tags’][‘environmentName’], ‘/flows/’,workflow()?[‘name’], ‘/runs/’,
workflow()?[‘run’][‘name’]).

Send an email

We are now ready to test the Flow. To do this I am going to add an action to the Main Scope that I know will fail. I am going to add a Get item action where I’ll attempt to get an item that does not exist from a SharePoint list.

Get item

The example Flow I’m using for this blog post has a manual trigger so I can test by clicking the Test button at the top-right of the Flow designer.

Looking at the Flow run history you’ll see that the Get item action failed which took us into the Fail or Timeout scope where all the actions ran successfully.

Flow run history

Checking the email for the Rob Windsor account we find the email message generated by the Send an email action.

Flow failure notification message

Being able to notify a user that a Flow failed or timed out has value but being able to provide detail about what action(s) failed or timed out takes that value to the next level.

4 Responses to Microsoft Flow Error Handling

  1. Rob,
    This looks like a very interesting way to handle Flow errors but I must be missing something. I get an error in Flow when I “… set the From property value (marked as 1 in the screen capture) to the expression result(‘Main’)” for the Filter Array as per your instructions. Flow does not recognize “result” as an expression. What am I missing?

    Thanks,
    Norm

    • A couple things that may have caused issues:
      1) Can you confirm that you have a Scope action named Main, and
      2) You may need to change the single quote characters in the expression builder if you copied the text from the blog post.

      • Apologies, Rob. Copy/paste of those curly quotes got me. 😐 Works like a dream now. I very much like the approach and appreciate your help!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.