I’ve been banging on this drum for a while, but error handling is essential in all Flows that do some work in “production” data. Having Flows that fail is common, but failures may result in invalid data, information being sent to the wrong person, or worse.
But to do proper error handling, we need the correct strategy. There are many ways to do this, but my favorite is inherited from many programming languages. The “try, catch, finally.”
Concept
The concept is simple, separated into three parts:
- Try – This is where you’ll put your actions and “try” to execute them.
- Catch – If the actions have an error, we’ll “catch” it and deal with it.
- Finally – In the end, we’ll do the cleanup regardless of there was an error or not.
It’s quite simple, but we don’t have that in Power Automate, so we need to be creative.
As always, I’ve built a template so that you don’t need to do all the work.
The template
The template is built using “scope actions” with some “compose actions” for the messages.
With this, you can add a new group of actions in your Flow and control if they fail or not. All logic will be inside the Scope action, so you can add multiple sequential “blocks” of “try, catch, finally” and control how your Flow will act in each “section.”
The try
Let’s look at the “try” part of the “try, catch, finally.”
The compose will contain the description of the “try, catch, finally” block. This will be used in the error messages so that you can have, for example, “Build Email: Failed.”
In the example above, we have a compose that will fail to test the whole template in action.
The catch
Now the “catch” part of the “try, catch, finally.”
This is where all the “magic” happens if something goes wrong. To achieve this, we need to configure the “Configure run after” for each of them to catch individual errors. For example, in the “Failed,” we do:
And we only set the “has failed” option.
We repeat for all the others, to get the same result.
The compose action will contain the error message that you want to send when something goes wrong. I added the prefix of the previous compose action to get the name plus the error message.
The finally
Now the “finally” part of the “try, catch, finally.”
This action will always run, so keep this in mind when adding actions here. To do this, we configure the “Configure Run After” will all options selected for all previous scope actions.
I’ve added a compose so that you have a message that you can use to be consistent with all the others.
This must always run because you may need to do some actions even if there are errors in the previous steps. If not, keep it like it is, and your Flow will continue.
Testing the Flow
Let’s do a simple test. We’ll define a variable with a “null” value and then try to convert that number into an int in the “try” part. We would get a failure that our Flow will “catch” in the first branch of the tree.
We’ll get:
How to use it?
There are 2 ways of using it.
- I’ll upload the template into my Power Automate Cookbook. You can download it directly here. If you don’t know how to import it, here are the instructions.
- Copy and paste. Yeah, this is awesome.
Power Automate supports copy and paste of actions. Here’s how to do it:
When you add a new action, you’ll get the option.
Now the cool part. You can have the template in a text file, copy and then paste it into any Flow that you have. To do that, here’s the code of the full template:
{"id":"85d28dc3-6461-4253-a581-0342-770d59ad","brandColor":"#8C3900","connectionReferences":{},"connectorDisplayName":"Control","icon":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDMyIDMyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KIDxwYXRoIGQ9Im0wIDBoMzJ2MzJoLTMyeiIgZmlsbD0iIzhDMzkwMCIvPg0KIDxwYXRoIGQ9Im04IDEwaDE2djEyaC0xNnptMTUgMTF2LTEwaC0xNHYxMHptLTItOHY2aC0xMHYtNnptLTEgNXYtNGgtOHY0eiIgZmlsbD0iI2ZmZiIvPg0KPC9zdmc+DQo=","isTrigger":false,"operationName":"ACTION_A","operationDefinition":{"type":"Scope","actions":{"CATCH_FAILED":{"type":"Scope","actions":{"FAILED_MESSAGE":{"type":"Compose","inputs":"@{outputs('ACTION_DESCRIPTION')}: Failed","runAfter":{}}},"runAfter":{"TRY":["Failed"]},"description":"This will catch the failed actions. These can be of any number of reasons so pay special attention to this one."},"CATCH_SKIPPED":{"type":"Scope","actions":{"MESSAGE_SKIPPPED":{"type":"Compose","inputs":"@{outputs('ACTION_DESCRIPTION')}: Action skipped","runAfter":{}}},"runAfter":{"TRY":["Skipped"]},"description":"Sometimes skipping is not a valid option, so this can either be an error or not. That's why we're separating this one from the rest. Deal with it if you need it."},"CATCH_TIMEOUT":{"type":"Scope","actions":{"TIMEOUT_MESSAGE":{"type":"Compose","inputs":"@{outputs('ACTION_DESCRIPTION')}: Timeout detected. Please review the actions","runAfter":{}}},"runAfter":{"TRY":["TimedOut"]},"description":"Timeouts can be an issue with the Flow but, sometimes, they are issues with other services. Pay attention to this one and monitor any service that is \"slow\" to execute"},"FINALLY":{"type":"Scope","actions":{"FINALLY_MESSAGE":{"type":"Compose","inputs":"@{outputs('ACTION_DESCRIPTION')}: Finally Reached","runAfter":{},"description":"If you have a lot somewhere, you can insert here the message and use it in your Flow. You can even use it in combination with the action description for better clarity in your Flows"}},"runAfter":{"CATCH_FAILED":["Succeeded","Failed","Skipped","TimedOut"],"CATCH_TIMEOUT":["Succeeded","Failed","Skipped","TimedOut"],"CATCH_SKIPPED":["Succeeded","Failed","Skipped","TimedOut"]},"description":"This action will run regardless of what happens. Put here any action that you need to happen if there's an error or not"},"ACTION_DESCRIPTION":{"type":"Compose","inputs":"Action A","runAfter":{},"description":"This the action's description that will be used in the notifications sent if something goes wrong."},"TRY":{"type":"Scope","actions":{},"runAfter":{"ACTION_DESCRIPTION":["Succeeded"]},"description":"This is where your code should be. Put here all the actions that you want to validate and parse in case of errors"}},"runAfter":{},"description":"This is your primary action. Add a description to the compose so that the error messages go with a context of what action failed. Add any activities that you want to try inside the TRY. Only then you'll get the proper error handling."}}
Copy the code and check again “My Clipboard” when you add a new action. You’ll get this:
How awesome is that?!? You can have a macro, text snippet, or anything else that copies the text to the clipboard, and you’ll have the template always available.
Final thoughts
I like the “try, catch, finally” strategy because it provides us with a way to deal with issues and has our Flows running smoothly.
Having the block of “actions” available with a simple copy & paste is a game-changer. You make them as complete as you want and then add them to your Flows with a few clicks.
Photo by Brett Jordan on Unsplash
hello Manuel,
Have you found a way to manually “Break” out of the TRY block?
eg. in my try block, i want to create an error, and skip to the CATCH block to elegantly handle it.
Adam has suggested a manual way to exit out of the TRY block using an HTTP action that will intentionally fail
https://powerusers.microsoft.com/t5/Building-Flows/Breaking-out-of-Scope/m-p/956609/highlight/true#M134091
i want wondering if you had any thoughts on how to do this in a more elegant way?
thank you
Hi Cameron,
You have a fascinating use case there. Adam’s solution makes sense, but then you would have your “normal” errors mixed with your “I want to continue” errors.
Can you have a segmentation by a variable or state, for example? What I mean is that at the point where you want to jump set a variable to “something” and then have a Condition action that will have the “normal” set of actions, and the other doesn’t do anything. This way, your action will end nicely and proceed to the next stage of action.
This will make things a bit more complex since you have to have more conditions, but at least you know that if the Flow fails, then it’s a failure that you need to deal with. It’s up to you how you want to interpret the results, but I would try to make things “Flow” in either direction depending on “I want to continue” or “do all the actions”.
Makes sense, or do I make things more complex? 😀
Great info. Thanks!