flowable/flowable-engine · error · ActivitiException
Cannot throw signal event
Error message
Cannot throw signal event '<eventName>' because execution '<executionId>' is suspended
What it means
SignalEventReceivedCmd throws ActivitiException when the execution referenced by executionId is suspended, preventing a signal event from being thrown into it. Suspended executions must not receive events until activated, so the command aborts, guarding the process state machine against modifications during suspension.
Solutions
- Resume with runtimeService.activateProcessInstanceById(instanceId) before signaling.
- Buffer the event externally (queue/DB) and deliver it once the instance is activated.
- Check suspension state via ProcessInstanceQuery.suspended() and defer or discard the signal.
Example fix
// before
runtimeService.signalEventReceived("order-approved", executionId);
// after
if (runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).suspended().count() == 0) {
runtimeService.signalEventReceived("order-approved", executionId);
} else {
// buffer event for delivery after activation
} Defensive patterns
Strategy: validation
Validate before calling
boolean suspended = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).suspended().count() > 0; if (!suspended) runtimeService.signalEventReceived(eventName, executionId);
Try / catch
try {
runtimeService.signalEventReceived(eventName, executionId);
} catch (ActivitiException e) {
logger.warn("Execution {} suspended; buffering signal {}", executionId, eventName);
eventBuffer.add(new PendingSignal(eventName, executionId));
} Prevention
- Subscribe external listeners to the suspension lifecycle so event delivery can be paused.
- Buffer inbound events while instances are under maintenance suspension.
When it happens
Trigger: Calling runtimeService.signalEventReceived(eventName, executionId) while the instance or execution was paused via suspendProcessInstanceById / suspendProcessInstanceByProcessDefinitionId.
Common situations: Maintenance suspension active when an external event (approval callback, message-queue listener) tries to deliver a signal; bulk suspension sweep racing with event delivery.
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
- Cannot find execution with id
- Execution ' ' has not subscribed to a signal event with…
- process instance is suspended, cannot set name
- A delegated task cannot be completed, but should be…
- Can not activate job
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/7cac5139a59dc273.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/cmd/SignalEventReceivedCmd.java:82
@Override
public Void execute(CommandContext commandContext) {
List<SignalEventSubscriptionEntity> signalEvents = null;
if (executionId == null) {
signalEvents = commandContext.getEventSubscriptionEntityManager().findSignalEventSubscriptionsByEventName(eventName, tenantId);
} else {
ExecutionEntity execution = commandContext.getExecutionEntityManager().findExecutionById(executionId);
if (execution == null) {
throw new ActivitiObjectNotFoundException("Cannot find execution with id '" + executionId + "'", Execution.class);
}
if (execution.isSuspended()) {
throw new ActivitiException("Cannot throw signal event '" + eventName
+ "' because execution '" + executionId + "' is suspended");
}
signalEvents = commandContext.getEventSubscriptionEntityManager().findSignalEventSubscriptionsByNameAndExecution(eventName, executionId);
if (signalEvents.isEmpty()) {
throw new ActivitiException("Execution '" + executionId + "' has not subscribed to a signal event with name '" + eventName + "'.");
}
}
for (SignalEventSubscriptionEntity signalEventSubscriptionEntity : signalEvents) {
// We only throw the event to globally scoped signals.
// Process instance scoped signals must be thrown within the process itself
if (signalEventSubscriptionEntity.isGlobalScoped()) {
signalEventSubscriptionEntity.eventReceived(payload, async);
}
}
View on GitHub (pinned to d6d39ce1c6)