conductor-oss/conductor · error · NonTransientException

Workflow id %s already belongs to parent workflow %s task %s

Error message

Workflow id %s already belongs to parent workflow %s task %s, cannot attach to parent workflow %s task %s

What it means

Thrown by validateIdempotentWorkflowOwnership() during startWorkflowIdempotent. When a workflow with the given ID already exists, Conductor verifies that the requested parentWorkflowId/parentWorkflowTaskId match the stored values. A mismatch means you are trying to attach an existing workflow to a different parent — which would corrupt the parent-child execution graph. This is a NonTransientException: no retry will change the outcome.

Source

Thrown at core/src/main/java/com/netflix/conductor/core/execution/WorkflowExecutorOps.java:2702

            StartWorkflowInput input, WorkflowModel existingWorkflow) {
        if (StringUtils.isBlank(input.getParentWorkflowId())
                && StringUtils.isBlank(input.getParentWorkflowTaskId())) {
            return;
        }

        if (!StringUtils.equals(input.getParentWorkflowId(), existingWorkflow.getParentWorkflowId())
                || !StringUtils.equals(
                        input.getParentWorkflowTaskId(),
                        existingWorkflow.getParentWorkflowTaskId())) {
            String message =
                    String.format(
                            "Workflow id %s already belongs to parent workflow %s task %s, cannot attach to parent workflow %s task %s",
                            existingWorkflow.getWorkflowId(),
                            existingWorkflow.getParentWorkflowId(),
                            existingWorkflow.getParentWorkflowTaskId(),
                            input.getParentWorkflowId(),
                            input.getParentWorkflowTaskId());
            throw new NonTransientException(message);
        }
    }

    private void createAndEvaluate(WorkflowModel workflow) {
        if (!executionLockService.acquireLock(workflow.getWorkflowId())) {
            throw new TransientException("Error acquiring lock when creating workflow: {}");
        }
        try {
            createAndEvaluateWithLock(workflow);
        } finally {
            executionLockService.releaseLock(workflow.getWorkflowId());
        }
    }

    private void createAndEvaluateWithLock(WorkflowModel workflow) {
        executionDAOFacade.createWorkflow(workflow);
        LOGGER.debug(
                "A new instance of workflow: {} created with id: {}",

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Use a unique workflowId per idempotent start — do not reuse IDs across different parent contexts.
  2. If the existing workflow is stale, remove it (DELETE /api/workflow/{workflowId}) and retry the idempotent start.
  3. Verify that the parentWorkflowId and parentWorkflowTaskId passed in StartWorkflowInput match those of the original creation.
  4. Audit your SubWorkflow task implementation to ensure it generates unique, parent-scoped workflow IDs.

Example fix

// before
StartWorkflowInput input = StartWorkflowInput.builder()
    .workflowId("my-fixed-id")
    .parentWorkflowId(newParentId)
    .parentWorkflowTaskId(newParentTaskId)
    .build();
workflowExecutor.startWorkflowIdempotent(input);

// after
String wfId = UUID.randomUUID().toString(); // unique per start
StartWorkflowInput input = StartWorkflowInput.builder()
    .workflowId(wfId)
    .parentWorkflowId(newParentId)
    .parentWorkflowTaskId(newParentTaskId)
    .build();
workflowExecutor.startWorkflowIdempotent(input);
Defensive patterns

Strategy: validation

Validate before calling

// Before idempotent start with a parent, check if workflow exists
WorkflowModel existing = null;
try {
    existing = executionDAOFacade.getWorkflowModelFromExecutionDAO(workflowId, false);
} catch (NotFoundException ignored) {}
if (existing != null) {
    if (!StringUtils.equals(input.getParentWorkflowId(), existing.getParentWorkflowId())
            || !StringUtils.equals(input.getParentWorkflowTaskId(), existing.getParentWorkflowTaskId())) {
        throw new IllegalStateException("Workflow already attached to a different parent");
    }
}
workflowExecutor.startWorkflowIdempotent(input);

Prevention

When it happens

Trigger: Calling startWorkflowIdempotent with workflowId X and parentWorkflowId P2, but workflow X was originally created as a child of parent P1. The existing workflow's parentWorkflowId or parentWorkflowTaskId does not equal the ones in the current request.

Common situations: Two different parent workflows both supplying the same hardcoded workflowId for their children. A bug in the sub-workflow task that generates duplicate workflow IDs. Attempting to 'reparent' a workflow by re-issuing an idempotent start with different parent parameters.

Related errors


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