conductor-oss/conductor · error · TerminateWorkflowException

Dynamic tasks could not be created. The value of %s from tas

Error message

Dynamic tasks could not be created. The value of %s from task's input %s has no dynamic tasks to be scheduled

What it means

Thrown by getDynamicForkJoinTasksAndInput() (the legacy path) when objectMapper.convertValue() produces a null DynamicForkJoinTaskList from the input at the dynamicForkJoinTasksParam key. This means the parameter value was null or could not be converted to a DynamicForkJoinTaskList, so there are no dynamic tasks to fork. Note: convertValue of null input returns null rather than throwing.

Source

Thrown at core/src/main/java/com/netflix/conductor/core/execution/mapper/ForkJoinDynamicTaskMapper.java:569

     * @throws TerminateWorkflowException : In case of the {@link WorkflowTask#getInputParameters()}
     *     does not have a payload that contains the list of the dynamic tasks
     */
    @VisibleForTesting
    Pair<List<WorkflowTask>, Map<String, Map<String, Object>>> getDynamicForkJoinTasksAndInput(
            WorkflowTask workflowTask, WorkflowModel workflowModel, Map<String, Object> input)
            throws TerminateWorkflowException {
        String dynamicForkJoinTaskParam = workflowTask.getDynamicForkJoinTasksParam();
        Object paramValue = input.get(dynamicForkJoinTaskParam);
        DynamicForkJoinTaskList dynamicForkJoinTaskList =
                objectMapper.convertValue(paramValue, DynamicForkJoinTaskList.class);

        if (dynamicForkJoinTaskList == null) {
            String reason =
                    String.format(
                            "Dynamic tasks could not be created. The value of %s from task's input %s has no dynamic tasks to be scheduled",
                            dynamicForkJoinTaskParam, input);
            LOGGER.error(reason);
            throw new TerminateWorkflowException(reason);
        }

        Map<String, Map<String, Object>> dynamicForkJoinTasksInput = new HashMap<>();

        List<WorkflowTask> dynamicForkJoinWorkflowTasks =
                dynamicForkJoinTaskList.getDynamicTasks().stream()
                        .peek(
                                dynamicForkJoinTask ->
                                        dynamicForkJoinTasksInput.put(
                                                dynamicForkJoinTask.getReferenceName(),
                                                dynamicForkJoinTask
                                                        .getInput())) // TODO create a custom pair
                        // collector
                        .map(
                                dynamicForkJoinTask -> {
                                    WorkflowTask dynamicForkJoinWorkflowTask = new WorkflowTask();
                                    dynamicForkJoinWorkflowTask.setTaskReferenceName(
                                            dynamicForkJoinTask.getReferenceName());

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Ensure the input map contains a non-null value at the dynamicForkJoinTasksParam key.
  2. Verify the dynamicForkJoinTasksParam name matches the key produced by the upstream task.
  3. If the dynamic tasks list may be legitimately empty, handle it upstream (e.g., skip the fork via a preceding SWITCH).
  4. Prefer the newer getDynamicForkTasksAndInput path (using dynamicForkTaskParam and dynamicForkTasksInputParamName) for new workflows.

Example fix

// before — missing param in input
WorkflowTask wt = new WorkflowTask();
wt.setDynamicForkJoinTasksParam("dynamicTasks");
// task input = { "otherKey": [...] }  // 'dynamicTasks' not present

// after — ensure upstream populates the key
// task input = { "dynamicTasks": [{ "taskName": "http", "referenceName": "ht0", ... }] }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure dynamicForkJoinTasksParam has a non-null value
String param = workflowTask.getDynamicForkJoinTasksParam();
Object paramValue = input.get(param);
if (paramValue == null) {
    throw new IllegalStateException(
        "Missing dynamic tasks input at key: " + param);
}
DynamicForkJoinTaskList list = objectMapper.convertValue(paramValue,
    DynamicForkJoinTaskList.class);
if (list == null || list.getDynamicTasks() == null || list.getDynamicTasks().isEmpty()) {
    throw new IllegalStateException("No dynamic tasks to schedule at key: " + param);
}

Prevention

When it happens

Trigger: The workflowTask.getDynamicForkJoinTasksParam() names a key that is absent from the task input map (resolves to null). The value at that key is present but has a shape that converts to a null DynamicForkJoinTaskList. The dynamicForkJoinTasksParam property on the WorkflowTask is misconfigured or empty.

Common situations: An upstream task that should populate the dynamic tasks list failed or produced null output. The parameter name in the workflow definition's dynamicForkJoinTasksParam does not match the key used by the upstream task. The workflow was designed for the newer getDynamicForkTasksAndInput path but uses the legacy param.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/ee39b12030a91d41. Report an issue: GitHub.