flowable/flowable-engine · error · FlowableException
Execution has no parent execution " +…
Error message
Execution has no parent execution " + execution.getParentId()
What it means
During doMoveExecutionState, before moving, the code ensures it is not operating on the root execution: a null parentId means the execution is the process-instance root and cannot be deleted/re-parented as part of the move. The message is misleading — it always interpolates null since it fires only when getParentId() == null.
Solutions
- Ensure the source activity ids map to leaf/concurrent executions, not the root process instance execution
- Check that filtered executions exclude the process-instance-type execution before building the move container
- If implementing a custom dynamic state manager, exclude root executions from the move set
Example fix
// before List<ExecutionEntity> toMove = executions; // after List<ExecutionEntity> toMove = executions.stream().filter(e -> e.getParentId() != null).collect(toList());
Defensive patterns
Strategy: validation
Validate before calling
if (execution.isProcessInstanceType() || execution.getParentId() == null) throw new IllegalStateException("Root execution cannot be moved"); Type guard
boolean isMovable(ExecutionEntity e) { return e.getParentId() != null; } Try / catch
try { builder.changeState(); } catch (FlowableException e) { if (e.getMessage().startsWith("Execution has no parent")) { /* exclude root execution from move set */ } else throw e; } Prevention
- Filter process-instance-type executions out of move containers
- Never pass scope/root ids as move activity ids
- Test custom dynamic state managers against concurrent executions
When it happens
Trigger: A move/change-state operation resolving to the root process-instance execution as one of the executions to move (e.g. source activity id accidentally matches the process instance scope, or move container resolved the root execution).
Common situations: Passing the process instance's own scope id as an activity id; move containers built from executions lacking currentActivityId filtering; custom subclasses of AbstractDynamicStateManager feeding wrong executions.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- A process instance id is required, but the provided id
- Cannot associate execution by id: no execution with id '
- Cannot find execution with id
- Cannot find process instance with id
- Cannot find process instance with id
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/2d30345018f7d404.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/dynamic/AbstractDynamicStateManager.java:555
executionEntity.setProcessDefinitionId(processInstanceChangeState.getProcessDefinitionToMigrateTo().getId());
childExecutionsToKeep.add(executionEntity.getId());
}
}
}
}
}
}
}
}
executionEntityManager.deleteChildExecutions(execution, childExecutionsToKeep, null, "Change parent activity to " + flowElementIdsLine, true, null);
if (!moveExecutionContainer.isDirectExecutionMigration()) {
executionEntityManager.deleteExecutionAndRelatedData(execution, "Change activity to " + flowElementIdsLine, false, false, true, execution.getCurrentFlowElement());
}
// Make sure we are not moving the root execution
if (execution.getParentId() == null) {
throw new FlowableException("Execution has no parent execution " + execution.getParentId());
}
// Delete the parent executions for each current execution when the move to activity id has the same subProcess scope
ExecutionEntity continueParentExecution;
if (processInstanceChangeState.getProcessDefinitionToMigrateTo() != null) {
continueParentExecution = deleteDirectParentExecutions(execution.getParentId(), moveToFlowElements,
executionIdsNotToDelete, processInstanceChangeState.getProcessDefinitionToMigrateTo(), moveExecutionContainer, commandContext);
} else {
continueParentExecution = deleteParentExecutions(execution.getParentId(), moveToFlowElements, executionIdsNotToDelete, commandContext);
}
moveExecutionContainer.addContinueParentExecution(execution.getId(), continueParentExecution);
}
List<ExecutionEntity> newChildExecutions = createEmbeddedSubProcessAndExecutions(moveToFlowElements, executionsToMove, moveExecutionContainer, processInstanceChangeState, commandContext);
if (moveExecutionContainer.isMoveToSubProcessInstance()) {
CallActivity callActivity = moveExecutionContainer.getCallActivity();
Process subProcess = moveExecutionContainer.getSubProcessModel().getProcessById(moveExecutionContainer.getSubProcessDefKey());View on GitHub (pinned to d6d39ce1c6)