This post will show you how to handle errors properly in Power Automate (formerly Microsoft Flow), including expected errors from APIs and connectors, and also how to deal with being throttled.
Overview
Power Automate’s default response to errors from connectors is pretty simple – exit the workflow right there, and record the entire run as a failure. In most cases this is what you might want, however sometimes you need to handle an error yourself and take action on it, or ignore it and move on, similar to a try-catch approach in many programming languages.
For example, before committing a record, you might want to check if it already exists first. If it does, then perform an update, if it doesn’t, go ahead and create it. When calling a RESTful web service to fetch a record by a unique ID, if it can’t be found, the service will most likely return a 404 status code. In Flow, a 404 is considered an error, and the workflow will fail and terminate at that point unless additional error handling is implemented. In this case though, a 404 shouldn’t be considered an error per se – it’s a legitimate response that tells you something, which you want to then handle and move on from.
To handle an error in Flow, you have to first configure the Run After behavior of your action that you want to happen after the error. You can configure the Run After behavior by clicking the ellipsis (…) on the title bar of an Action, and choosing Configure run after.
The default setting for every action is to only run if the previous action was successful. If the previous action generates an error, then the workflow will exit before executing the subsequent action. To handle an error then, you will need to make the subsequent action run even if the previous action failed, which you can enable with the “has failed” checkbox.
In the image above, I have a SharePoint GetItem action followed by a Switch action, and the Switch is set to run if the SharePoint action fails or is successful.
Handling Status Codes
The great thing about the Connectors in the Power Platform is that they are built on web service standards. Each connector is basically a wrapper around a first party or third party web service, and leverages HTTP requests under the hood to communicate. Since each request through a connector is just a web service call, then we should be able to get at the status code response, the headers that the server sent back, and the body of the response.
Power Automate exposes all of this to us via Expressions, which are built using the Azure Logic Apps Workflow Definition Language. Using the outputs() function in an Expression, we are able to get at the complete HTTP response from a connector action. Check out the nice docs for this function, where you can see a sample JSON response from a Twitter GetUser action:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
{ "statusCode": 200, "headers": { "Pragma": "no-cache", "Vary": "Accept-Encoding", "x-ms-request-id": "a916ec8f52211265d98159adde2efe0b", "X-Content-Type-Options": "nosniff", "Timing-Allow-Origin": "*", "Cache-Control": "no-cache", "Date": "Mon, 09 Apr 2018 18:47:12 GMT", "Set-Cookie": "ARRAffinity=b9400932367ab5e3b6802e3d6158afffb12fcde8666715f5a5fbd4142d0f0b7d;Path=/;HttpOnly;Domain=twitter-wus.azconn-wus.p.azurewebsites.net", "X-AspNet-Version": "4.0.30319", "X-Powered-By": "ASP.NET", "Content-Type": "application/json; charset=utf-8", "Expires": "-1", "Content-Length": "339" }, "body": { "FullName": "Contoso Corporation", "Location": "Generic Town, USA", "Id": 283541717, "UserName": "ContosoInc", "FollowersCount": 172, "Description": "Leading the way in transforming the digital workplace.", "StatusesCount": 93, "FriendsCount": 126, "FavouritesCount": 46, "ProfileImageUrl": "https://pbs.twimg.com/profile_images/908820389907722240/gG9zaHcd_400x400.jpg" } } |
Notice the collection of headers we have access to, the body of the response, and the statusCode.
Using this, we can write Conditions that check the return status code and handle errors accordingly. The syntax for getting the HTTP Status Code in an Expression is like this:
1 |
outputs('your_action_name').statusCode |
Note that your action name needs to be in single quotes (not double!), and if you have spaces in your Action name (which most do), you’ll have to escape them with underscores instead.
A really nice pattern for error handling is to use a Switch action, and use the above formula in the “On” field. Click in this field, and click the Expression tab. Type this formula and click the OK button to insert your expression.
Then you can create a Case for each expected status code. For example, Case ‘200’, you can then Update the item, Case ‘404’ create a new item, and Case ‘500’ terminate the workflow with an error message (because something unrecoverably bad probably happened).
Below you can see an image of a Flow where I am looking for a specific item by ID from SharePoint, and a Switch that runs if that action succeeds or fails, and then processes 200, 404, and anything else in separate cases:
And here you can see it running with a 404 failure code (I looked for an item with ID 256, which does not exist), and see how it ran the 404 case in the Switch:
Handling Throttling Responses
When you get throttled by a web service, it will usually return a 429 status code. These are handled already by Power Automate, so you don’t have to handle it yourself with home grown looping retry logic. Power Automate already has built-in mechanisms to handle throttling, including automatic retries and exponential back-offs.
You can configure the throttle response behavior by clicking the Ellipsis (…) on the Action title bar, and choosing Settings.
Near the bottom of the page, you’ll find the settings for Retry Policy. The default is an Exponential retry with 4 attempts with 2 attempts (EDIT:11/19/2019, just announced the day I posted this article, this has been changed from 4 to 2, https://flow.microsoft.com/en-us/blog/october-updates-for-microsoft-flow/). You can configure total # of retries, back-off approach (fixed or exponential), and intervals. Notice that 429 (too many requests), 408 (request timeout), and 5XX (internal server error) errors are handled in this way for you.
When you handle the error in this way, does the flow still get marked as ‘failed’? I have a similar flow where I’m checking to see if a file exists and using the 404 response as a method to know. But even though the flow continues after that failure, the entire flow is marked as ‘failed’. Any way around this that you found?
You can have two paralel branches: one for the actions when the previous one succeeded, and the other when it failed. At the end of this second branch you can add a ‘Compose’ action block and assign it a WDL expression designed to fail always, for example:
split(‘qwerty’,’a’)[1]
Use the Terminate action at the end of your branch and choose the Success option. That’ll force the flow to appear as successful.