conductor-oss/conductor · error · NonTransientException

Tasks of multiple workflows cannot be created/updated simult

Error message

Tasks of multiple workflows cannot be created/updated simultaneously

What it means

validateTasks throws NonTransientException when the supplied task list spans more than one workflowInstanceId. The Cassandra DAO writes tasks for a single workflow per batch, so mixed-workflow batches are a programming error, not a retriable fault. NonTransientException is NOT retried by the framework RetryTemplate.

Source

Thrown at cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraExecutionDAO.java:844

        Preconditions.checkNotNull(tasks, "Tasks object cannot be null");
        Preconditions.checkArgument(!tasks.isEmpty(), "Tasks object cannot be empty");
        tasks.forEach(
                task -> {
                    Preconditions.checkNotNull(task, "task object cannot be null");
                    Preconditions.checkNotNull(task.getTaskId(), "Task id cannot be null");
                    Preconditions.checkNotNull(
                            task.getWorkflowInstanceId(), "Workflow instance id cannot be null");
                    Preconditions.checkNotNull(
                            task.getReferenceTaskName(), "Task reference name cannot be null");
                });

        String workflowId = tasks.get(0).getWorkflowInstanceId();
        Optional<TaskModel> optionalTask =
                tasks.stream()
                        .filter(task -> !workflowId.equals(task.getWorkflowInstanceId()))
                        .findAny();
        if (optionalTask.isPresent()) {
            throw new NonTransientException(
                    "Tasks of multiple workflows cannot be created/updated simultaneously");
        }
    }

    @VisibleForTesting
    WorkflowMetadata getWorkflowMetadata(String workflowId) {
        ResultSet resultSet =
                session.execute(selectTotalStatement.bind(UUID.fromString(workflowId)));
        recordCassandraDaoRequests("getWorkflowMetadata");
        return Optional.ofNullable(resultSet.one())
                .map(
                        row -> {
                            WorkflowMetadata workflowMetadata = new WorkflowMetadata();
                            workflowMetadata.setTotalTasks(row.getInt(TOTAL_TASKS_KEY));
                            workflowMetadata.setTotalPartitions(row.getInt(TOTAL_PARTITIONS_KEY));
                            return workflowMetadata;
                        })
                .orElseThrow(

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Group tasks by workflowInstanceId before calling createTasks/updateTasks; write one batch per workflow.
  2. Add a precondition at the call site that all tasks share the same workflowInstanceId.
  3. Fix the upstream accumulator so it never mixes workflows into one list.
  4. Write a unit test asserting single-workflow batches to prevent regression.

Example fix

// before
tasks.forEach(t -> allTasks.add(t)); // mixes workflows
executionDAO.createTasks(allTasks); // throws

// after
tasks.stream()
    .collect(Collectors.groupingBy(TaskModel::getWorkflowInstanceId))
    .values()
    .forEach(executionDAO::createTasks);
Defensive patterns

Strategy: validation

Validate before calling

// Group tasks by workflow before persisting; never mix workflows in one batch
Map<String, List<TaskModel>> byWorkflow = tasks.stream()
    .collect(Collectors.groupingBy(TaskModel::getWorkflowInstanceId));
byWorkflow.values().forEach(executionDAO::createTasks);

Type guard

public boolean isSingleWorkflowBatch(List<TaskModel> tasks) {
    if (tasks == null || tasks.isEmpty()) return false;
    String wf = tasks.get(0).getWorkflowInstanceId();
    return tasks.stream().allMatch(t -> wf.equals(t.getWorkflowInstanceId()));
}

Try / catch

try {
    executionDAO.createTasks(tasks);
} catch (NonTransientException e) {
    // programmer error: mixed-workflow batch — do NOT retry; fix grouping upstream
    LOGGER.error("Refusing mixed-workflow task batch", e);
    throw e;
}

Prevention

When it happens

Trigger: Calling createTasks/updateTasks with a List<TaskModel> whose members have different workflowInstanceId values — e.g. concatenating tasks from two workflows before persisting.

Common situations: A batch-accumulation bug where a shared list collects tasks across workflows; refactoring that broke per-workflow grouping; incorrect test fixtures.

Related errors


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