flowable/flowable-engine · error · FlowableException
Cannot propagate escalation '" + escalationName + "' with co
Error message
Cannot propagate escalation '" + escalationName + "' with code '" + escalationCode + "', because " + boundaryExecution + " is suspended
What it means
EscalationPropagation.executeEventHandler throws this when a thrown escalation is caught by a boundary escalation event whose execution is currently suspended. The engine refuses to deliver the escalation into a suspended scope, since resumed processing of a suspended execution is not allowed.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/EscalationPropagation.java:217
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
ExecutionEntity eventSubProcessExecution = executionEntityManager.createChildExecution(parentExecution);
eventSubProcessExecution.setCurrentFlowElement(event.getSubProcess() != null ? event.getSubProcess() : event);
CommandContextUtil.getAgenda().planContinueProcessOperation(eventSubProcessExecution);
} else {
ExecutionEntity boundaryExecution = null;
List<? extends ExecutionEntity> childExecutions = parentExecution.getExecutions();
for (ExecutionEntity childExecution : childExecutions) {
if (childExecution != null
&& childExecution.getActivityId() != null
&& childExecution.getActivityId().equals(event.getId())) {
boundaryExecution = childExecution;
}
}
if (boundaryExecution != null && boundaryExecution.isSuspended()) {
throw new FlowableException(
"Cannot propagate escalation '" + escalationName + "' with code '" + escalationCode + "', because " + boundaryExecution
+ " is suspended");
}
CommandContextUtil.getAgenda().planTriggerExecutionOperation(boundaryExecution);
}
}
protected static Map<String, List<Event>> findCatchingEventsForProcess(String processDefinitionId, String escalationCode) {
Map<String, List<Event>> eventMap = new HashMap<>();
Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);
List<EventSubProcess> subProcesses = process.findFlowElementsOfType(EventSubProcess.class, true);
for (EventSubProcess eventSubProcess : subProcesses) {
for (FlowElement flowElement : eventSubProcess.getFlowElements()) {
if (flowElement instanceof StartEvent startEvent) {
if (CollectionUtil.isNotEmpty(startEvent.getEventDefinitions()) && startEvent.getEventDefinitions()View on GitHub (pinned to d6d39ce1c6)
Solutions
- Resume the suspended execution/process instance (RuntimeService.activateProcessInstanceById / activate the relevant scope) before the escalation is thrown.
- If suspension is intentional, delay or suppress the escalation source (e.g. gate the throwEscalation path) until the scope is active.
- Check suspension state programmatically before triggering the escalation: query the execution and skip/queue if ExecutionEntity.isSuspended().
- Review which execution was suspended — suspending the parent instance suspends children; activate children explicitly if only the parent should resume.
Example fix
// before
runtimeService.throwEscalation(processInstanceId, "escalationCode"); // may hit suspended boundary execution
// after
if (!runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult().isSuspended()) {
runtimeService.throwEscalation(id, "escalationCode");
} else {
runtimeService.activateProcessInstanceById(id); // then throw
} Defensive patterns
Strategy: validation
Validate before calling
ProcessInstance pi = runtimeService.createProcessInstanceQuery()
.processInstanceId(piId).singleResult();
if (pi != null && pi.isSuspended()) {
runtimeService.activateProcessInstanceById(piId); // before throwing escalation
} Try / catch
try {
runtimeService.throwEscalation(piId, code);
} catch (FlowableException e) {
if (e.getMessage().contains("is suspended")) {
runtimeService.activateProcessInstanceById(piId);
}
} Prevention
- Check isSuspended() on the target instance before throwing escalations.
- Align suspension/resumption lifecycle with escalation sources.
- Include subprocess/call-activity scopes in suspension audits.
When it happens
Trigger: A subprocess (or call activity) throws an escalation; a boundary escalation event on that subprocess matches (by escalation code or default catch), but the childExecution holding the boundary event subscription is suspended (e.g. via RuntimeService.suspendProcessInstanceById or suspendJob for the scope).
Common situations: Suspending a process instance for maintenance/BAU hold while it (or its subprocess) later throws an escalation; suspension state persisted across restarts colliding with an incoming escalation from a call activity; resuming logic that activates the parent but not the child execution holding the boundary subscription.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- BPMN XSD could not be found
- The bpmn 2.0 xml is not properly encoded
- The ${task} cannot be deleted because is part of a running p
- ${sequenceFlowId} does not match a sequence flow for ${deleg
- Null execution passed
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/9c3151a4efd03991.
Report an issue: GitHub.