Power Automate (Microsoft Flow) Error Handling

Published on Author Rob Windsor31 Comments

If you search for information on Power Automate (Microsoft Flow) error handling you’ll find that the 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. Power Automate 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.

31 Responses to Power Automate (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.

  2. Rob,

    Thank you for your clear and good explanation, it makes things very clear. Now I have one question, I implemented your general idea, but in my flow that’s ‘only’ the beginning. 5000 files from SharePoint are initialized, and in this process sometimes an error occurs. The owner of the flow is notified of this error, and the Flow should continue nonetheless. Any other errors (not foreseen) should cause the Flow to stop functioning. How can I do this.
    Now, eventhough I used this catch technique, and that works succesful, still the Flow fails and stops.

  3. Great explanation on solid error handling. However I have a problem similar to Norm Martin, but I can not get the EDI to accept the result(…) function no matter how I write statement; double quotes, singles quotes etc. Is it no longer possible to use Azure functions in PowerAutomate?

    • I’m not sure how you are relating Azure function and Power Automate. When you said Azure functions, did you mean Logic Apps functions?

  4. I’ve got several Flows which are having failures due to various performance issues on the systems I am connecting to, being able to report on “what type” of error was run into will be great.

    However… when I try to add the “result” function to my Filter Array, it can’t find it? When I scroll down to the “Workflow” functions in the Expression list… it only shows two: “listCallbackURL” and “workflow”, with no “show more” option like some of the other groupings include. Looking through the online docs, there should be quite a few more functions listed here?

  5. this is a really good post and bailed me out quickly. The error handling does not really provide good details. In my flow I am updating a sharepoint list, I can not validate the date in sharepoint because of a locale issue, so users enter their data into a test field and the flow writes it to a number field. As long as the user enters the number as “1,2” or “1.2” it will be converted to a decimal and written to the number field. there are about 50 fields and if it fails on the update I would like to be able to identify what field it failed at. I receive in the flow an InvalidTemplate at column ‘2345″ or some other number, but that is not helpful. IS there a way to identify that column and pass it to the error message variable?

  6. Hi Rob,

    Excellent post. This is exactly something I have been looking for. I’m curious, is there an advantage to the parallel “Success” and “Fail or Timeout” scopes vs. the linear Try, Catch, Finally scopes that I have seen proposed by Pieter Veenstra? Is it just a style preference?

    Thanks
    Ken

  7. This method is great for identifying an error state, but does not give much detail. It looks like MS has changed the error reporting method recently and I am able to pull the detailed error message from an action with body(”)[‘errors’]. Unfortunately, I haven’t figured out a way to make this statement dynamic – you have to reference a particular action (can’t use variables or nested statements).

    • I’m not aware of the errors property. I’ll do some investigation on it and update this post or write a new one if I find anything.

      Thanks.

    • Hi Chris,

      Could you elaborate more on what you mentioned about body(”)[‘errors’] with example. That would be great.

      Thanks

  8. I’m trying to get this to work but I keep getting the error that it needs to end with a response action. I have put one of these in each of the last scopes on the parallel branch ends and also tried one connected to the end of both branch ends but I still get the error. Any ideas?

  9. Hi Rob,

    Thank you for this! Very helpful. The implementation I used was slightly different. Instead of a filter on the result object, I simply passed the object directly into an Apply to Each loop, used Parse JSON to retrieve the properties, then set a variable with the values that I wanted.

    One thing that might be helpful for other readers is that the result object can be called using the following:
    @{result(‘Try_Scope_or_Action_Name’)}

    Or the following when passing it through Expression to create the object:
    result(‘Try_Scope_or_Action_Name’)

  10. If you cannot get the result function to work, does your scope name contain spaces? If so, replace spaces with underscore/underline. πŸ™‚

  11. Good article! I have solved it in a similar way, but I am strugelling with hierarchical result structures. e.g. the failed action is in a branch of a condition action. In that case I get the result of the condition action, but not the result from the action in the branch when I use Filter Array.

    Does the Filter Array function traverse hierarchies? I would assume not, but maybe I am doing it wrong. Does anyone have experience with this use case?

      • Hi Bernhard and Ignacio,

        Unfortunately, I have not found a good way to traverse hierarchies. You would have to add an error check after each container (Condition, Loop, child Scope, etc.) to catch the error coming out of it. Doing so defeats the entire purpose of the pattern. Hopefully Power Automate will eventually address this so we can have global error handlers that work in all cases.

  12. Hi Rob,

    Great post. I am using the Search users (V2) connector, attempting to test email addresses in a SharePoint library to see if they are in our Active directory. I’ve been testing the output of the connector for “AccountEnabled” but when it hits a bad address, it throws an error and quits. I put your “three scopes” framework up and so far, the failure does not ever go down the failure leg of the Flow (it is configured to run on failure only). Obviously I am missing something applying your technique. Can you tell me how I should approach this problem?

    • Hi Anne,

      Sorry for the delayed reply. Can you elaborate on what you mean by a “bad address”? When I use “Search for users (V2)”, it just returns an empty array when it I give it an email address that does not exist. It does not throw an error.

Leave a Reply to Ken Kapp Cancel 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.