flowable/flowable-engine · error · FlowableException

has not subscribed to a signal event with name ' '.

Error message

${execution} has not subscribed to a signal event with name '${eventName}'.

What it means

The given execution exists and is active, but no signal event subscription with the supplied name is registered on it. Signals delivered to a specific execution must match a signal boundary/intermediate-catch event waiting in that execution; otherwise Flowable throws instead of silently dropping the event.

Solutions

  1. Confirm the BPMN node is a signal catch/boundary event and its signal name exactly matches the eventName passed (case-sensitive).
  2. Find valid targets with runtimeService.createExecutionQuery().signalEventSubscriptionName(eventName).list() and use one of those execution ids.
  3. Handle double-delivery: query the subscription first and skip if absent (idempotent signaling).

Example fix

// before
runtimeService.signalEventReceived("OrderPaid", executionId);
// after
if (!runtimeService.createExecutionQuery().executionId(executionId)
        .signalEventSubscriptionName("OrderPaid").list().isEmpty()) {
    runtimeService.signalEventReceived("OrderPaid", executionId);
}
Defensive patterns

Strategy: validation

Validate before calling

boolean waiting = !runtimeService.createExecutionQuery()
    .executionId(executionId)
    .signalEventSubscriptionName(signalName).list().isEmpty();
if (waiting) runtimeService.signalEventReceived(signalName, executionId);

Try / catch

try {
    runtimeService.signalEventReceived(signalName, executionId);
} catch (FlowableException e) {
    if (e.getMessage().contains("has not subscribed")) {
        log.info("No active subscription for signal {} on {}", signalName, executionId);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling runtimeService.signalEventReceived(eventName, executionId) where the execution is not currently waiting at a signal catch event with that name (wrong name, event already fired, or execution is a parent not at the wait state).

Common situations: Typo or case mismatch in the signal name between BPMN and caller; duplicate signal delivery after the first one already advanced the token; signaling the process instance execution instead of the execution waiting at the boundary event.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/8542e3cd0f925740. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/SignalEventReceivedCmd.java:99

            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
            if (signalEventSubscriptionEntity.isGlobalScoped()) {

                if (executionId == null && Flowable5Util.isFlowable5ProcessDefinitionId(commandContext, signalEventSubscriptionEntity.getProcessDefinitionId())) {
                    Flowable5CompatibilityHandler compatibilityHandler = Flowable5Util.getFlowable5CompatibilityHandler();
                    compatibilityHandler.signalEventReceived(signalEventSubscriptionEntity, payload, async);

                } else {
                    processEngineConfiguration.getEventDispatcher().dispatchEvent(
                            FlowableEventBuilder.createSignalEvent(FlowableEngineEventType.ACTIVITY_SIGNALED, signalEventSubscriptionEntity.getActivityId(), eventName,
                                    payload, signalEventSubscriptionEntity.getExecutionId(), signalEventSubscriptionEntity.getProcessInstanceId(),
                                    signalEventSubscriptionEntity.getProcessDefinitionId()), processEngineConfiguration.getEngineCfgKey());

View on GitHub (pinned to d6d39ce1c6)