'C# How to get exact error message from Logic App triggered by HttpRequest instead of default error message?

I have a simple console application and it calls a Logic App by HttpRequest.

When the Logic App fails at any step I want to get exact the error message saying why it fails.

In the Logic App I can see the error.

Example: in the image, it fails at step 2 which it can't convert a string into an int. It's saying:

InvalidTemplate. Unable to process template language expressions in action 'Parse_JSON' inputs at line '0' and column '0': 'Required property 'content' expects a value but got null. Path ''.'.

which is what's I expect.

enter image description here

Here is my Logic App design:

enter image description here

But when I debug in a console application, it gives me a message "The server did not receive a response from an upstream server. Request tracking id 'some random Ids'." which is not very useful.

Here is my console application:

var obj = new
        {
            Age = "Twenty",
            Name = "James"
        };
        using (var client = new HttpClient())
        {
            var content = new StringContent(JsonConvert.SerializeObject(obj));
            content.Headers.ContentType.MediaType = "application/json";
            var response = await client.PostAsync(url, content);
            var errorMessage = await response.Content.ReadAsStringAsync();
            //errorMessage: {"error":{"code":"NoResponse","message":"The server did not receive a response from an upstream server. Request tracking id 'some random Ids'."}}
        }

So is there anyway to make the C# response return the error message in the step 2 of the Logic App?

What I expect is:

InvalidTemplate. Unable to process template language expressions in action 'Parse_JSON' inputs at line '0' and column '0': 'Required property 'content' expects a value but got null. Path ''.'.

Not:

{"error":{"code":"NoResponse","message":"The server did not receive a response from an upstream server. Request tracking id 'some random Ids'."}}

Thank you in advanced.



Solution 1:[1]

You can use actions('<Your_Previous_Step>')['error'] in your case actions('Parse_JSON')['error'] doing so you can able to retrieve the error message of that particular action.

Here is my logic app

enter image description here

I'm testing this through postman. Below is the response I received in postman.

enter image description here

Make sure you set Configure run after options to make the flow work even after it gets failed.

enter image description here

Updated Answer (General Solution)

In this case you can initialise a string variable and then add Append to string variable for each step so that it can catch the previous steps error. Below is the screenshot of my logic app.

enter image description here

Response in my postman

enter image description here

NOTE: Make sure you set Configure run after property for each action.

Solution 2:[2]

You can use the Scope action to encase the vast majority of other actions and then if something fails, you can catch the step for which it fails at.

You can load this JSON definition into your own tenant and see a working version.

{
    "definition": {
        "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
        "actions": {
            "Filter_array": {
                "inputs": {
                    "from": "@variables('Result')",
                    "where": "@equals(item()['status'], 'Failed')"
                },
                "runAfter": {
                    "Initialize_Result": [
                        "Succeeded"
                    ]
                },
                "type": "Query"
            },
            "Initialize_Error_Message": {
                "inputs": {
                    "variables": [
                        {
                            "name": "Error Message",
                            "type": "string",
                            "value": "@{body('Filter_array')[0]['error']['message']}"
                        }
                    ]
                },
                "runAfter": {
                    "Filter_array": [
                        "Succeeded"
                    ]
                },
                "type": "InitializeVariable"
            },
            "Initialize_Integer_Variable": {
                "inputs": {
                    "variables": [
                        {
                            "name": "Integer Variable",
                            "type": "integer",
                            "value": 1
                        }
                    ]
                },
                "runAfter": {},
                "type": "InitializeVariable"
            },
            "Initialize_Result": {
                "inputs": {
                    "variables": [
                        {
                            "name": "Result",
                            "type": "array",
                            "value": "@result('Scope')"
                        }
                    ]
                },
                "runAfter": {
                    "Scope": [
                        "Succeeded",
                        "FAILED"
                    ]
                },
                "type": "InitializeVariable"
            },
            "Scope": {
                "actions": {
                    "Set_Integer_Variable_(Step_1)": {
                        "inputs": {
                            "name": "Integer Variable",
                            "value": 2
                        },
                        "runAfter": {},
                        "type": "SetVariable"
                    },
                    "Set_Integer_Variable_(Step_2)": {
                        "inputs": {
                            "name": "Integer Variable",
                            "value": "@string('Test')"
                        },
                        "runAfter": {
                            "Set_Integer_Variable_(Step_1)": [
                                "Succeeded"
                            ]
                        },
                        "type": "SetVariable"
                    },
                    "Set_Integer_Variable_(Step_3)": {
                        "inputs": {
                            "name": "Integer Variable",
                            "value": 3
                        },
                        "runAfter": {
                            "Set_Integer_Variable_(Step_2)": [
                                "Succeeded"
                            ]
                        },
                        "type": "SetVariable"
                    }
                },
                "runAfter": {
                    "Initialize_Integer_Variable": [
                        "Succeeded"
                    ]
                },
                "type": "Scope"
            }
        },
        "contentVersion": "1.0.0.0",
        "outputs": {},
        "parameters": {},
        "triggers": {
            "Recurrence": {
                "evaluatedRecurrence": {
                    "frequency": "Month",
                    "interval": 12
                },
                "recurrence": {
                    "frequency": "Month",
                    "interval": 12
                },
                "type": "Recurrence"
            }
        }
    },
    "parameters": {}
}

Naturally, it's a little more intensive and follows the same principals as a normal flow for continuing to the next step after a failure but this will help you with larger flows.

This is what the test flow looks like ...

Flow

To explain it quickly, the middle steps are simple Set Variable actions that can be changed to cause the failure.

In the definition I've given you, step 2 will fail but you can change it to step 1 or 3 and you should still see the error come out at the end regardless of the step in the scope action that fails.

I suggest playing with it and looking at the output to the scope action, which is written to variable Result in the Initialize Result step.

For reference, this is the sort of information that comes out of the Scope action that you can use to determine what has failed.

{
    "variables": [
        {
            "name": "Result",
            "type": "Array",
            "value": [
                {
                    "name": "Set_Integer_Variable_(Step_1)",
                    "inputs": {
                        "name": "Integer Variable",
                        "value": 2
                    },
                    "outputs": {
                        "body": {
                            "name": "Integer Variable",
                            "value": 2
                        }
                    },
                    "startTime": "2022-04-22T06:55:57.8965917Z",
                    "endTime": "2022-04-22T06:55:57.9281959Z",
                    "trackingId": "0c93fa70-a552-4776-bce1-8ac889933de9",
                    "clientTrackingId": "08585509963278112157168286283CU11",
                    "status": "Succeeded"
                },
                {
                    "name": "Set_Integer_Variable_(Step_2)",
                    "startTime": "2022-04-22T06:55:57.9434709Z",
                    "endTime": "2022-04-22T06:55:57.9434709Z",
                    "trackingId": "f82b494b-0ecd-412b-887a-d4b08f4a5751",
                    "clientTrackingId": "08585509963278112157168286283CU11",
                    "code": "BadRequest",
                    "status": "Failed",
                    "error": {
                        "code": "BadRequest",
                        "message": "The variable 'Integer Variable' of type 'Integer' cannot be initialized or updated with value of type 'String'. The variable 'Integer Variable' only supports values of types 'Integer'."
                    }
                },
                {
                    "name": "Set_Integer_Variable_(Step_3)",
                    "startTime": "2022-04-22T06:55:57.9590957Z",
                    "endTime": "2022-04-22T06:55:57.9590957Z",
                    "trackingId": "f761d71f-8ec0-4a29-9a8a-a39a81faf660",
                    "clientTrackingId": "08585509963278112157168286283CU11",
                    "code": "ActionSkipped",
                    "status": "Skipped",
                    "error": {
                        "code": "ActionConditionFailed",
                        "message": "The execution of template action 'Set_Integer_Variable_(Step_3)' is skipped: the 'runAfter' condition for action 'Set_Integer_Variable_(Step_2)' is not satisfied. Expected status values 'Succeeded' and actual value 'Failed'."
                    }
                }
            ]
        }
    ]
}

Take note, you still need to apply the Configure run after properties to ensure it continues on after the Scope action finishes ...

Run After

You'd need to put some more error checking in but my suggestion would be to wrap all of that functionality into another LogicApp that you can reuse across your tenant. That's the thinking anyway.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2