flowable/flowable-engine · error · FlowableException
Call activity '" + executionActivityId + "' loop…
Error message
Call activity '" + executionActivityId + "' loop characteristics differs in new model. It must be mapped explicitly for migration (or all its child activities)
What it means
Thrown when a call activity with running unmapped children exists in both models but exactly one of the models declares multi-instance loop characteristics for it. A change in loop cardinality/structure of an actively running multi-instance call activity cannot be auto-migrated, so an explicit mapping is required.
Solutions
- Add an explicit activity mapping for the call activity in the migration document
- Keep loop characteristics identical in the target model version
- Terminate or complete the running multi-instance children before migrating
- Redesign the migration in steps: complete the MI branch, then migrate to the new model
Example fix
// before
// callActivity had no MI in v1, got multiInstanceLoopCharacteristics in v2, unmapped
// after
migrationBuilder.addActivityMapping("miCallActivity", "miCallActivity"); Defensive patterns
Strategy: validation
Validate before calling
boolean oldMI = ((CallActivity) oldModel.getFlowElement(id)).hasMultiInstanceLoopCharacteristics();
boolean newMI = ((CallActivity) newModel.getFlowElement(id)).hasMultiInstanceLoopCharacteristics();
if (oldMI ^ newMI) { /* explicit mapping required */ } Try / catch
try {
migrationBuilder.migrate(instanceId);
} catch (FlowableException e) {
if (e.getMessage().contains("loop characteristics differs")) {
// add explicit mapping or keep MI configuration identical
}
} Prevention
- Avoid adding/removing multi-instance on activities that can be running during migration
- Stage such refactors behind a new activity id
- Validate migrations in CI against realistic running instances
- Map MI call activities explicitly by default
When it happens
Trigger: Migrating instances where the call activity had multi-instance characteristics added or removed in the new model (XOR of hasMultiInstanceLoopCharacteristics is true) and no explicit mapping exists.
Common situations: Adding a multi-instance (parallel/sequential) wrapper to a previously simple call activity, or removing it, in a new definition version while instances are mid-flight inside that call activity.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Call activity '" + executionActivityId + "' does not exist…
- Call activity '" + executionActivityId + "' has a different…
- Call activity '" + executionActivityId + "' is not a Call…
- Cannot autoMap activity migration for '" +…
- Cannot complete process instance. Parent process instance
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/75f4a0d3d5c058bc.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/migration/ProcessInstanceMigrationManagerImpl.java:701
if (!childSubProcessExecutionActivityIds.isEmpty()) {
runningChildrenNotFullyMapped = true;
break;
}
}
}
if (!subProcessActivityMappingsByCallActivityIdAndFromActivityId.containsKey(executionActivityId) || runningChildrenNotFullyMapped) {
//If there are running child activities not mapped, the call activity must be equally valid in the new model, the activityId in the new model must refer also to a callActivity with matching callElement
FlowElement newModelFlowElement = newModel.getFlowElement(executionActivityId);
if (newModelFlowElement == null) {
throw new FlowableException("Call activity '" + executionActivityId + "' does not exist in the new model. It must be mapped explicitly for migration (or all its child activities)");
}
if (newModelFlowElement instanceof CallActivity) {
if (!referToSameCalledElement((CallActivity) currentModelFlowElement, (CallActivity) newModelFlowElement)) {
throw new FlowableException("Call activity '" + executionActivityId + "' has a different called element in the new model. It must be mapped explicitly for migration (or all its child activities)");
}
if (((CallActivity) currentModelFlowElement).hasMultiInstanceLoopCharacteristics() ^ ((CallActivity) newModelFlowElement).hasMultiInstanceLoopCharacteristics()) {
throw new FlowableException("Call activity '" + executionActivityId + "' loop characteristics differs in new model. It must be mapped explicitly for migration (or all its child activities)");
}
} else {
throw new FlowableException("Call activity '" + executionActivityId + "' is not a Call Activity in the new model. It must be mapped explicitly for migration (or all its child activities)");
}
}
}
String flowElementMultiInstanceParentId = getFlowElementMultiInstanceParentId(currentModelFlowElement);
if (flowElementMultiInstanceParentId != null && mappedFromActivities.contains(flowElementMultiInstanceParentId)) {
// Add the parent MI execution activity Id to be explicitly mapped...
if (!executionActivityIdsToMapExplicitly.contains(flowElementMultiInstanceParentId)) {
executionActivityIdsToMapExplicitly.add(flowElementMultiInstanceParentId);
}
// The root executions are the ones to migrate and are explicitly mapped
List<ExecutionEntity> miRootExecutions = (List<ExecutionEntity>) executionEntityManager.findInactiveExecutionsByActivityIdAndProcessInstanceId(flowElementMultiInstanceParentId, processInstanceExecution.getId());
filteredExecutionsByActivityId.put(flowElementMultiInstanceParentId, miRootExecutions);
} else {View on GitHub (pinned to d6d39ce1c6)