Severity
P3 - Medium (Minor functionality affected)
Describe the Bug with repro steps
In the example below
The scope "My_Scope" has Status of "Failed".
There is an exception handler Exception_Handler set to
"runAfter": {
"My_Scope": [
"FAILED",
"TIMEDOUT"
]
After running the test BugRepro_FunctionFailed_ExceptionHandlerMissing the "My_Scope" action has Status of "Failed" but testRun.Actions does not contain the Exception_Handler action.
Why not? It should have been called if "My_Scope" has Status of "Failed"?
What type of Logic App Is this happening in?
Standard (Local Development)
Are you experiencing a regression?
No response
Which operating system are you using?
Windows
Did you refer to the TSG before filing this issue? https://aka.ms/lauxtsg
Yes
Workflow JSON
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"outputs": {},
"triggers": {
"manual": {
"type": "Request",
"kind": "Http",
"inputs": {
"schema": {
"type": "object",
"properties": {
"input": { "type": "string" }
}
}
}
}
},
"actions": {
"My_Scope": {
"type": "Scope",
"actions": {
"Call_Function": {
"type": "InvokeFunction",
"inputs": {
"functionName": "MyFunction",
"parameters": {
"input": "@triggerBody()?['input']"
}
},
"runAfter": {}
}
},
"runAfter": {}
},
"Exception_Handler": {
"type": "Scope",
"actions": {
"Filter_Errors": {
"type": "Query",
"inputs": {
"from": "@result('My_Scope')",
"where": "@not(equals(item()?['status'], 'Succeeded'))"
},
"runAfter": {}
},
"Compose_Code": {
"type": "Compose",
"inputs": {
"code": "@coalesce(body('Filter_Errors')?[0]?['error']?['code'], 500)",
"message": "@coalesce(body('Filter_Errors')?[0]?['error']?['message'], 'An unexpected error occurred')"
},
"runAfter": {
"Filter_Errors": [ "SUCCEEDED" ]
}
},
"Return_Response": {
"type": "Response",
"inputs": {
"statusCode": "@outputs('Compose_Code')?['code']",
"body": { "error": true }
},
"runAfter": {
"Compose_Code": [ "SUCCEEDED" ]
}
},
"Terminate_Exception": {
"type": "Terminate",
"inputs": {
"runStatus": "Failed",
"runError": {
"code": "@outputs('Compose_Code')?['code']",
"message": "Exception caught"
}
},
"runAfter": {
"Return_Response": [ "SUCCEEDED" ]
}
}
},
"runAfter": {
"My_Scope": [
"FAILED",
"TIMEDOUT"
]
}
}
}
},
"kind": "Stateful"
}
Screenshots or Videos
No response
Environment
Additional context
using Microsoft.Azure.Workflows.UnitTesting;
using Microsoft.Azure.Workflows.UnitTesting.Definitions;
using Microsoft.Azure.Workflows.UnitTesting.ErrorResponses;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Tests.LogicApp.BugRepro_InvokeFunction_ScopeFailure.Test
{
/// <summary>
/// Minimal reproduction of a Logic Apps Unit Testing Framework bug (extension v1.127.24.0).
///
/// BUG: When an InvokeFunction action inside a Scope is mocked as Failed (TestErrorInfo),
/// AND the Exception_Handler scope (runAfter: FAILED/TIMEDOUT) contains:
/// 1. A Query action using @result('ScopeName') to get scope results
/// 2. A Compose action using @coalesce(body('Filter_Errors')...) referencing Query output
/// then the framework fails to include Exception_Handler in testRun.Actions.
/// The Exception_Handler is never evaluated despite the scope failing.
///
/// Without the @coalesce(body('Filter_Errors')...) expression → passes.
/// Without the @result('My_Scope') Query → passes.
/// With both present → Exception_Handler is missing from testRun.Actions.
///
/// Workaround: Mock the InvokeFunction as Succeeded with outputs that cause
/// a downstream action (e.g. ParseJson) to fail naturally, instead of using TestErrorInfo.
///
/// Workflow structure:
/// My_Scope (Scope)
/// └── Call_Function (InvokeFunction)
/// Exception_Handler (Scope, runAfter: My_Scope [FAILED, TIMEDOUT])
/// ├── Filter_Errors (Query, from: @result('My_Scope'))
/// ├── Compose_Code (Compose, @coalesce(body('Filter_Errors')...))
/// ├── Return_Response (Response)
/// └── Terminate_Exception (Terminate, Failed)
/// </summary>
[TestClass]
public class BugRepro_InvokeFunctionScopeFailureTest
{
/// <summary>
/// CONTROL: Function succeeds → Exception_Handler is skipped. Confirms workflow is valid.
/// </summary>
[TestMethod]
public async Task Control_FunctionSucceeds_ExceptionHandlerSkipped()
{
var executor = new TestExecutor("BugRepro_InvokeFunction_ScopeFailure/testSettings.config");
var triggerMock = new Mocks.BugRepro_InvokeFunction_ScopeFailure.TriggerMock();
var functionMock = new Mocks.BugRepro_InvokeFunction_ScopeFailure.CallFunctionActionMock(
name: "Call_Function");
var testMock = new TestMockDefinition(
triggerMock: triggerMock,
actionMocks: new Dictionary<string, ActionMock>
{
{ functionMock.Name, functionMock }
});
var testRun = await executor.Create().RunWorkflowAsync(testMock: testMock);
Assert.AreEqual(TestWorkflowStatus.Succeeded, testRun.Status,
"Workflow should succeed when function succeeds");
Assert.IsTrue(testRun.Actions.ContainsKey("Exception_Handler"),
"Exception_Handler should be present (as Skipped)");
Assert.AreEqual(TestWorkflowStatus.Skipped, testRun.Actions["Exception_Handler"].Status);
}
/// <summary>
/// BUG REPRO: Function mocked as Failed via TestErrorInfo.
///
/// EXPECTED: My_Scope fails → Exception_Handler runs (Filter_Errors → Compose_Code →
/// Return_Response → Terminate_Exception).
/// ACTUAL: testRun.Actions only contains My_Scope. Exception_Handler is missing.
///
/// Root cause: The combination of a Query action using @result('My_Scope') and a
/// Compose action referencing body('Filter_Errors') via @coalesce() causes the
/// framework to skip the Exception_Handler entirely when an InvokeFunction inside
/// the scope is mocked as Failed with TestErrorInfo.
/// </summary>
[TestMethod]
public async Task BugRepro_FunctionFailed_ExceptionHandlerMissing()
{
var executor = new TestExecutor("BugRepro_InvokeFunction_ScopeFailure/testSettings.config");
var triggerMock = new Mocks.BugRepro_InvokeFunction_ScopeFailure.TriggerMock();
var error = new TestErrorInfo(
Microsoft.Azure.Workflows.Common.ErrorResponses.ErrorResponseCode.ActionFailed,
"Simulated function failure");
var functionMock = new Mocks.BugRepro_InvokeFunction_ScopeFailure.CallFunctionActionMock(
status: TestWorkflowStatus.Failed,
name: "Call_Function",
error: error);
var testMock = new TestMockDefinition(
triggerMock: triggerMock,
actionMocks: new Dictionary<string, ActionMock>
{
{ functionMock.Name, functionMock }
});
var testRun = await executor.Create().RunWorkflowAsync(testMock: testMock);
// Diagnostic output
System.Console.WriteLine($"\nWorkflow Status: {testRun.Status}");
System.Console.WriteLine($"Actions: {string.Join(", ", testRun.Actions.Keys)}");
foreach (var a in testRun.Actions)
{
System.Console.WriteLine($" {a.Key}: {a.Value.Status}");
if (a.Value.ChildActions != null)
foreach (var c in a.Value.ChildActions)
System.Console.WriteLine($" {c.Key}: {c.Value.Status}");
}
// ASSERT
Assert.AreEqual(TestWorkflowStatus.Failed, testRun.Status,
"Workflow should be Failed");
Assert.IsTrue(testRun.Actions.ContainsKey("My_Scope"),
"My_Scope should be present");
Assert.AreEqual(TestWorkflowStatus.Failed, testRun.Actions["My_Scope"].Status);
// BUG: This assertion fails — Exception_Handler is not in testRun.Actions
Assert.IsTrue(testRun.Actions.ContainsKey("Exception_Handler"),
"BUG: Exception_Handler is missing from testRun.Actions. "
+ "The framework skips the Exception_Handler when a Query uses @result('ScopeName') "
+ "and a Compose uses @coalesce(body('Filter_Errors')...), combined with "
+ "an InvokeFunction mocked as Failed via TestErrorInfo.");
}
}
}
namespace Tests.LogicApp.Mocks.BugRepro_InvokeFunction_ScopeFailure
{
// ── Trigger ──
public class TriggerMock : Microsoft.Azure.Workflows.UnitTesting.Definitions.TriggerMock
{
public TriggerMock(TestWorkflowStatus status = TestWorkflowStatus.Succeeded,
string name = null, TriggerOutput outputs = null)
: base(status: status, name: name, outputs: outputs ?? new TriggerOutput())
{
}
}
public class TriggerOutput : MockOutput
{
public JObject Body { get; set; }
public TriggerOutput()
{
this.Body = new JObject
{
["input"] = "test"
};
}
}
// ── Call_Function (InvokeFunction) ──
public class CallFunctionActionMock : ActionMock
{
/// <summary>Constructor for successful mock with outputs.</summary>
public CallFunctionActionMock(TestWorkflowStatus status = TestWorkflowStatus.Succeeded,
string name = null, CallFunctionActionOutput outputs = null)
: base(status: status, name: name, outputs: outputs ?? new CallFunctionActionOutput())
{
}
/// <summary>Constructor for failed mock with TestErrorInfo.</summary>
public CallFunctionActionMock(TestWorkflowStatus status, string name = null, TestErrorInfo error = null)
: base(status: status, name: name, error: error)
{
}
}
public class CallFunctionActionOutput : MockOutput
{
public JObject Body { get; set; }
public CallFunctionActionOutput()
{
this.Body = new JObject
{
["result"] = "ok"
};
}
}
}
Severity
P3 - Medium (Minor functionality affected)
Describe the Bug with repro steps
In the example below
The scope "My_Scope" has Status of "Failed".
There is an exception handler
Exception_Handlerset toAfter running the test
BugRepro_FunctionFailed_ExceptionHandlerMissingthe "My_Scope" action has Status of "Failed" buttestRun.Actionsdoes not contain theException_Handleraction.Why not? It should have been called if "My_Scope" has Status of "Failed"?
What type of Logic App Is this happening in?
Standard (Local Development)
Are you experiencing a regression?
No response
Which operating system are you using?
Windows
Did you refer to the TSG before filing this issue? https://aka.ms/lauxtsg
Yes
Workflow JSON
{ "definition": { "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", "contentVersion": "1.0.0.0", "outputs": {}, "triggers": { "manual": { "type": "Request", "kind": "Http", "inputs": { "schema": { "type": "object", "properties": { "input": { "type": "string" } } } } } }, "actions": { "My_Scope": { "type": "Scope", "actions": { "Call_Function": { "type": "InvokeFunction", "inputs": { "functionName": "MyFunction", "parameters": { "input": "@triggerBody()?['input']" } }, "runAfter": {} } }, "runAfter": {} }, "Exception_Handler": { "type": "Scope", "actions": { "Filter_Errors": { "type": "Query", "inputs": { "from": "@result('My_Scope')", "where": "@not(equals(item()?['status'], 'Succeeded'))" }, "runAfter": {} }, "Compose_Code": { "type": "Compose", "inputs": { "code": "@coalesce(body('Filter_Errors')?[0]?['error']?['code'], 500)", "message": "@coalesce(body('Filter_Errors')?[0]?['error']?['message'], 'An unexpected error occurred')" }, "runAfter": { "Filter_Errors": [ "SUCCEEDED" ] } }, "Return_Response": { "type": "Response", "inputs": { "statusCode": "@outputs('Compose_Code')?['code']", "body": { "error": true } }, "runAfter": { "Compose_Code": [ "SUCCEEDED" ] } }, "Terminate_Exception": { "type": "Terminate", "inputs": { "runStatus": "Failed", "runError": { "code": "@outputs('Compose_Code')?['code']", "message": "Exception caught" } }, "runAfter": { "Return_Response": [ "SUCCEEDED" ] } } }, "runAfter": { "My_Scope": [ "FAILED", "TIMEDOUT" ] } } } }, "kind": "Stateful" }Screenshots or Videos
No response
Environment
Additional context