flowable/flowable-engine · error · PvmException
couldn't process signal
Error message
couldn't process signal '<signalName>' on activity '<activityId>': <cause>
What it means
PvmException thrown by ExecutionEntity.signal when the process virtual machine fails to deliver a signal to the current activity. Any non-runtime exception during signaling (waiting-state continuation, event triggering) is wrapped into this message carrying the signal name, activity id, and cause message. It indicates the wait state could not be continued — the underlying cause is the real problem.
Solutions
- Inspect the wrapped cause (e.getCause()) — the PvmException message only carries cause.getMessage(); fix the underlying exception first
- Verify the execution is actually waiting at the activity being signaled and that the signal/event name matches the wait state's subscription
- Check any ExecutionListener/delegate classes on the signaled activity for bugs (constructor access, missing classes, thrown exceptions)
- Log execution.getId() and activity id, and confirm the process state in the database before retrying
Example fix
// before
execution.signal("resume", null); // cause hidden
// after
try {
execution.signal("resume", null);
} catch (PvmException e) {
Throwable cause = e.getCause();
log.error("Signal failed on activity: " + e.getMessage(), cause);
throw cause instanceof RuntimeException ? (RuntimeException) cause : e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// confirm the execution is waiting where you expect before signaling
Execution e = runtimeService.createExecutionQuery()
.executionId(executionId).activityId(expectedActivityId).singleResult();
if (e == null) throw new IllegalStateException("Execution not waiting at " + expectedActivityId); Try / catch
try {
execution.signal(signalName, signalData);
} catch (PvmException e) {
Throwable cause = e.getCause();
log.error("Signal '{}' on activity failed: {}", signalName, e.getMessage(), cause);
throw cause instanceof RuntimeException ? (RuntimeException) cause : new RuntimeException(cause);
} Prevention
- Always inspect getCause() — the message hides the root failure
- Match signal/event names exactly to the wait state's declaration
- Validate delegate/listener classes load and run before production
- Re-query execution state before signaling after concurrent modifications
When it happens
Trigger: Calling execution.signal(signalName, payload) or completing a wait state (receive task, user task via PVM internals, executionListener-triggered event) where the signaled activity's behavior throws a checked exception, e.g., a failing ExecutionListener, invalid event subscription, or a delegate throwing an Exception.
Common situations: Signaling an execution that has migrated to another activity, a delegate listener configured with a class that fails at runtime, sending a signal payload of the wrong type to a receive task, or triggering an event the activity is not actually waiting for.
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
- couldn't execute event listener :
- couldn't process signal
- A process instance id is required, but the provided id
- A process instance id is required, but the provided id
- A process instance id is required, but the provided id
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/80e8e8f6ea1c42bc.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/persistence/entity/ExecutionEntity.java:467
String signalledActivityId = activity.getId();
activityBehavior.signal(this, signalName, signalData);
// If needed, dispatch an event indicating an activity was signalled
boolean isUserTask = (activityBehavior instanceof UserTaskActivityBehavior)
|| ((activityBehavior instanceof MultiInstanceActivityBehavior)
&& ((MultiInstanceActivityBehavior) activityBehavior).getInnerActivityBehavior() instanceof UserTaskActivityBehavior);
if (!isUserTask && Context.getProcessEngineConfiguration() != null
&& Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createSignalEvent(
FlowableEngineEventType.ACTIVITY_SIGNALED, signalledActivityId, signalName, signalData, this.id, this.processInstanceId, this.processDefinitionId),
EngineConfigurationConstants.KEY_PROCESS_ENGINE_CONFIG);
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new PvmException("couldn't process signal '" + signalName + "' on activity '" + activity.getId() + "': " + e.getMessage(), e);
}
}
@Override
public void take(PvmTransition transition) {
take(transition, true);
}
/**
* @param fireActivityCompletionEvent This method can be called from other places (like {@link #takeAll(List, List)}), where the event is already fired. In that case, false is passed an no second event is fired.
*/
@Override
public void take(PvmTransition transition, boolean fireActivityCompletionEvent) {
if (fireActivityCompletionEvent) {
fireActivityCompletedEvent();
}
View on GitHub (pinned to d6d39ce1c6)