One of the biggest limitations of Power Automate Web is that there is no (obvious) functionality for an error handling block like a Try – Catch.

This guide will show you how to implement an error handling block using the Scope step.

Flow Time – Part 1 – Creating the Error Handler

Before we start updating all of our flows with some error handling logic, we will need to create a shared flow that will be called in the event of an error and generate an email notification.

Create a new flow with a manual trigger and the following parameters.

  • ResultSet will contain the error message, failure step, etc.
  • FlowDetails will contain the details (Name, URL) of the flow that failed
  • Email is an optional parameter that designates who will receive the email notification. You don’t have to include this if you want to hardcode a distribution.

The following section is entirely optional and depends on your setup. This section declares a variable to hold the final distribution and then sets it to either the optional email parameter or an email defined in an environment variable.

Next lets Select the error message from the ResultSet parameter that was passed in.

  • From: @{json(triggerBody()['text'])}
  • Step: @item()?['name']
  • Error: This logic will try to the find the value that is most likely to contain the error message. @if(or(equals(item()?['status'],'Failed'),not(equals(item()?['outputs/body/error/message'],null))),if(not(equals(item()?['error/message'],null)),item()?['error/message'],item()?['outputs/body/error/message']),null)

Next we Filter the output from the select to remove any empty error messages.

  • @body('Select')
  • @item()?['Error']
  • @null

Now we create an HTML table from our output for email readability.

  • @{body('Filter_array')}

Next we will generate a URL for the flow run so we can link back to it from an email.

@{concat('https://us.flow.microsoft.com/manage/environments/', json(triggerBody()['text_1'])['tags']['environmentName'], '/flows/', json(triggerBody()['text_1'])['name'], '/runs/', json(triggerBody()['text_1'])['run']['name'])}

Now we pull out the name of the flow just to make the email nicer.

  • @{json(triggerBody()['text_1'])?['tags']?['flowDisplayName']}

We can now send our email as follows. Make sure to switch to the HTML view and paste the entire snippet. I removed the <head> logic so the screenshot wasn’t ridiculous looking.

  • To: EmailToUse is the variable that was updated earlier with the email distribution.
  • From: @{outputs('Compose_-_Get_Flow_Name')}
  • Body:
<head>
       <style type="text/css">
         p {
            font-family: "Calibri", Arial, Helvetica, sans-serif;
            font-size: 14px;
        }
        table {         
            border-collapse: collapse;
        }
            td, th {
                border: 1px solid #ddd;
                padding: 8px;
                text-align: left;
                vertical-align:top;
            }
            tr:nth-child(even) {
                background-color: #e3e3e3;
            }
            tr:hover {
                background-color: #ddd;
            }
            th {
                padding-top: 5px;
                padding-bottom: 5px;
                text-align: center;
                background-color: #ededed;
                color: black;
            }
    </style>
</head>
<body>
<p>The <b>@{outputs('Compose_-_Get_Flow_Name')}</b> flow did not complete successfully due to the errors below.  <br>
@{body('Create_HTML_table')}
The flow execution can be reviewed <a href='@{outputs('Compose_-_Flow_Run_URL')}'>here</a></p>
</body>

For reference, this HTML will generate an email as follows.

Finally, we are going to be running this as a child flow that gets called on an error from ALL flows we are creating so we need to add a response step at the end.

IMPORTANT: In ALL response steps, make sure to go into the settings and set to asynchronous. If you do not, flow executions will sometimes duplicate.

Now you are all done. Make sure to define Run Only Users so that outlook has a defined connection and we are all set to use it from our flows.

Flow Time – Part 2 – How to use the error handler

Add a scope to your flow and label it as you prefer. For standardization purposes, i generally label it as Scope – Try.

I’ve added a compose in the middle to generate an error for this post. The formula is here if you are curious: div(10,0)

Inside of the Try block you will be adding all steps that you want to check for a failure on. Unfortunately, due to a system limitation you cannot add variable initialization steps in a Scope so try to use a Set Variable step in the try block if there is some logic that can potentially fail.

Below the Scope – Try add another scope called Scope – Catch which will contain the actions to perform if ANY step in the Scope – Try errors.

Go to the Configure run after setting in the Scope – Catch and check off has failed and has timed out. This will ensure that the actions in the Scope – Catch only execute in the event of a failure.

Now inside of the catch you will 3 steps as follows.

The Run a Child Flow is configured as per the below to use the flow we created earlier.

  • ResultSet: @{string(result('Scope_-_Try'))}
  • FlowDetails: @{string(workflow())}
  • Email: Enter an override if you have this parameter and want to overlay what’s in the flow.

A 500 code response to generate a failure. Dont forget to set to asynch in the settings!

Finally a terminate step because im paranoid. No idea if this is really needed.

Now that its all together. Congratulations! You now have dynamic error handling. Below is a screenshot of how all your flows should be organized.

Categorized in:

General,