flowable/flowable-engine · error · FlowableException
Cannot throw signal event '${eventName}' because ${execution
Error message
Cannot throw signal event '${eventName}' because ${execution} is suspended What it means
The target execution for a signal event exists but is suspended, and Flowable refuses to deliver the signal into a frozen execution. Signals are state-changing operations, so they are blocked while suspension is in effect.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/SignalEventReceivedCmd.java:87
@Override
public Void execute(CommandContext commandContext) {
List<SignalEventSubscriptionEntity> signalEvents = null;
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
EventSubscriptionService eventSubscriptionService = processEngineConfiguration.getEventSubscriptionServiceConfiguration().getEventSubscriptionService();
if (executionId == null) {
signalEvents = eventSubscriptionService.findSignalEventSubscriptionsByEventName(eventName, tenantId);
} else {
ExecutionEntity execution = CommandContextUtil.getExecutionEntityManager(commandContext).findById(executionId);
if (execution == null) {
throw new FlowableObjectNotFoundException("Cannot find execution with id '" + executionId + "'", Execution.class);
}
if (execution.isSuspended()) {
throw new FlowableException("Cannot throw signal event '" + eventName + "' because " + execution + " is suspended");
}
if (Flowable5Util.isFlowable5ProcessDefinitionId(commandContext, execution.getProcessDefinitionId())) {
Flowable5CompatibilityHandler compatibilityHandler = Flowable5Util.getFlowable5CompatibilityHandler();
compatibilityHandler.signalEventReceived(eventName, executionId, payload, async, tenantId);
return null;
}
signalEvents = eventSubscriptionService.findSignalEventSubscriptionsByNameAndExecution(eventName, executionId);
if (signalEvents.isEmpty()) {
throw new FlowableException(execution + " 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
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Activate the instance with runtimeService.activateProcessInstanceById(execution.getProcessInstanceId()) before signaling.
- Buffer the signal: store the event payload and deliver it after resumption (or via a job/retry).
- Check execution.isSuspended() (or the suspended flag on the query result) and handle gracefully in the caller.
Example fix
// before
runtimeService.signalEventReceived(eventName, executionId);
// after
Execution e = runtimeService.createExecutionQuery().executionId(executionId).singleResult();
if (e != null && !e.isSuspended()) {
runtimeService.signalEventReceived(eventName, executionId);
} Defensive patterns
Strategy: try-catch
Validate before calling
Execution e = runtimeService.createExecutionQuery().executionId(executionId).singleResult(); if (e != null && !e.isSuspended()) runtimeService.signalEventReceived(signalName, executionId);
Try / catch
try {
runtimeService.signalEventReceived(signalName, executionId);
} catch (FlowableException e) {
if (e.getMessage().contains("is suspended")) {
pendingSignalStore.save(signalName, executionId); // deliver after activation
} else throw e;
} Prevention
- Queue signals for suspended executions and flush on activation
- Check the suspended flag on the Execution query result before signaling
- Coordinate with admins: external events arriving during maintenance windows should be buffered
When it happens
Trigger: Calling runtimeService.signalEventReceived(eventName, executionId) on an execution suspended via suspendProcessInstanceById/DefinitionId or a suspend job definition.
Common situations: External events (payments, callbacks) arriving while an administrator suspended the process for maintenance; instances suspended because their process definition was suspended.
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
- process instance ${processInstanceId} is suspended, cannot s
- Task ${taskId} is already deleted
- a suspended
- Child task variables can only be set when starting a plan it
- Child form variables can only be set when starting a plan it
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/9bffdeaa2b7aeae0.
Report an issue: GitHub.