Describe the bug
When a workflow fails and triggers its failureWorkflow, Conductor puts the failed workflow object into the failure workflow's input under the key failedWorkflow. This object is a raw WorkflowModel Java instance, not a plain Map. As a result:
${workflow.input.failedWorkflow} resolves correctly, the full object is returned and serialized to JSON on persistence.
${workflow.input.failedWorkflow.someField} always resolves to null. JsonPath (using JsonSmartJsonProvider) cannot traverse into a Java POJO, and the error is silently swallowed by SUPPRESS_EXCEPTIONS.
The data is present. The path expression is correct. The failure is at the POJO boundary inside JsonPath.
Details
Conductor version: v3.30.2
Persistence: Postgres
Queue: Postgres
To Reproduce
- Define a workflow with
"failureWorkflow": "My Failure Workflow".
- Define
My Failure Workflow with a task whose inputParameters include:
"workflowName": "${workflow.input.failedWorkflow.workflowName}"
- Trigger the parent workflow and cause it to fail.
- Observe that
workflowName in the failure workflow task input is null.
To confirm the data is present, add a second parameter:
"fullWorkflow": "${workflow.input.failedWorkflow}"
This resolves to the complete workflow JSON including workflowName, proving the object is accessible, but nested path traversal into it fails.
Root cause
WorkflowExecutorOps.java, method terminateWorkflow(), around line 768:
Map<String, Object> input = new HashMap<>(workflow.getInput());
input.put("workflowId", workflowId);
input.put("reason", reason);
input.put("failureStatus", workflow.getStatus().toString());
input.put("failedWorkflow", workflow); // <-- raw WorkflowModel, not a Map
ParametersUtils.getTaskInputV2() then calls:
Configuration option = Configuration.defaultConfiguration().addOptions(Option.SUPPRESS_EXCEPTIONS);
DocumentContext documentContext = JsonPath.parse(inputMap, option);
JsonSmartJsonProvider (the default) cannot navigate into a Java POJO. When the path resolver reaches failedWorkflow and attempts to traverse further, it fails silently and returns null.
Expected behavior
${workflow.input.failedWorkflow.workflowName} and all other nested paths into failedWorkflow should resolve to the actual field values of the failed workflow.
Suggested fix
Serialize workflow to a plain Map before inserting it into the failure workflow input:
input.put("failedWorkflow", objectMapper.convertValue(workflow, Map.class));
Additional context
SUPPRESS_EXCEPTIONS in ParametersUtils.java makes this failure completely silent, no log line, no exception. The task simply receives null. This makes the bug very hard to diagnose without side-by-side comparison of ${workflow.input.failedWorkflow} (whole object, works) vs ${workflow.input.failedWorkflow.someField} (nested, null).
The same root cause affects GraalJS INLINE tasks: when failedWorkflow is forwarded via inputParameters, GraalJS receives the raw WorkflowModel as a Java interop object. Property access ($.failedWorkflow.workflowName) returns undefined because GraalJS does not automatically call bean getters under the configured HostAccess policy.
Describe the bug
When a workflow fails and triggers its
failureWorkflow, Conductor puts the failed workflow object into the failure workflow's input under the keyfailedWorkflow. This object is a rawWorkflowModelJava instance, not a plainMap. As a result:${workflow.input.failedWorkflow}resolves correctly, the full object is returned and serialized to JSON on persistence.${workflow.input.failedWorkflow.someField}always resolves tonull. JsonPath (usingJsonSmartJsonProvider) cannot traverse into a Java POJO, and the error is silently swallowed bySUPPRESS_EXCEPTIONS.The data is present. The path expression is correct. The failure is at the POJO boundary inside JsonPath.
Details
Conductor version: v3.30.2
Persistence: Postgres
Queue: Postgres
To Reproduce
"failureWorkflow": "My Failure Workflow".My Failure Workflowwith a task whoseinputParametersinclude:workflowNamein the failure workflow task input isnull.To confirm the data is present, add a second parameter:
This resolves to the complete workflow JSON including
workflowName, proving the object is accessible, but nested path traversal into it fails.Root cause
WorkflowExecutorOps.java, methodterminateWorkflow(), around line 768:ParametersUtils.getTaskInputV2()then calls:JsonSmartJsonProvider(the default) cannot navigate into a Java POJO. When the path resolver reachesfailedWorkflowand attempts to traverse further, it fails silently and returnsnull.Expected behavior
${workflow.input.failedWorkflow.workflowName}and all other nested paths intofailedWorkflowshould resolve to the actual field values of the failed workflow.Suggested fix
Serialize
workflowto a plainMapbefore inserting it into the failure workflow input:Additional context
SUPPRESS_EXCEPTIONSinParametersUtils.javamakes this failure completely silent, no log line, no exception. The task simply receivesnull. This makes the bug very hard to diagnose without side-by-side comparison of${workflow.input.failedWorkflow}(whole object, works) vs${workflow.input.failedWorkflow.someField}(nested, null).The same root cause affects GraalJS INLINE tasks: when
failedWorkflowis forwarded viainputParameters, GraalJS receives the rawWorkflowModelas a Java interop object. Property access ($.failedWorkflow.workflowName) returnsundefinedbecause GraalJS does not automatically call bean getters under the configuredHostAccesspolicy.