flowable/flowable-engine · error · FlowableException

signal() can only be called on a TriggerableActivityBehavior

Error message

signal() can only be called on a TriggerableActivityBehavior instance for + execution

What it means

ClassDelegate.trigger() only forwards a signal to the delegate behavior when the resolved ActivityBehavior instance implements TriggerableActivityBehavior. If it does not (or the delegate resolved to null), a FlowableException is thrown stating signal() requires a TriggerableActivityBehavior for the given execution. This protects against signaling an activity whose behavior cannot be triggered.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java:241

                if (!ErrorPropagation.mapException(e, (ExecutionEntity) execution, mapExceptions)) {
                    throw e;
                }
            }
        } else if (activityBehaviorInstance instanceof TriggerableActivityBehavior) {
            try {
                ((TriggerableActivityBehavior) activityBehaviorInstance).trigger(execution, signalName, signalData);
                if (triggerable) {
                    leave(execution);
                }
            } catch (BusinessError error) {
                ErrorPropagation.propagateError(error, execution);
            } catch (RuntimeException e) {
                if (!ErrorPropagation.mapException(e, (ExecutionEntity) execution, mapExceptions)) {
                    throw e;
                }
            }
        } else {
            throw new FlowableException("signal() can only be called on a " + TriggerableActivityBehavior.class.getName() + " instance for " + execution);
        }
    }

    // Subprocess activityBehaviour

    @Override
    public void completing(DelegateExecution execution, DelegateExecution subProcessInstance) throws Exception {
        if (activityBehaviorInstance == null) {
            activityBehaviorInstance = getActivityBehaviorInstance();
        }

        if (activityBehaviorInstance instanceof SubProcessActivityBehavior) {
            ((SubProcessActivityBehavior) activityBehaviorInstance).completing(execution, subProcessInstance);
        } else {
            throw new FlowableException("completing() can only be called on a " + SubProcessActivityBehavior.class.getName() + " instance for " + execution);
        }
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Only call runtimeService.trigger() on executions whose current behavior implements TriggerableActivityBehavior; check the wait state first.
  2. Make the delegate's ActivityBehavior implement TriggerableActivityBehavior (signal method) if it should accept signals.
  3. Implement the delegate as a JavaDelegate with triggerable=true (ServiceTaskJavaDelegateActivityBehavior with triggerable) so signal support is wired.
  4. Fix process design: replace the signal with the correct completion path (e.g. complete the user task or use a message/signal event).

Example fix

// before
executionEntity.trigger(); // works for any wait state
// after
if (executionEntity.getCurrentFlowElement() instanceof ServiceTask
        && behavior instanceof TriggerableActivityBehavior) {
    executionEntity.trigger();
} else {
    // use the appropriate completion API for this wait state
}
Defensive patterns

Strategy: type-guard

Validate before calling

Execution exec = runtimeService.createExecutionQuery().executionId(id).singleResult();
// only trigger executions waiting on a triggerable activity

Type guard

boolean canTrigger(ActivityBehavior b) { return b instanceof TriggerableActivityBehavior; }

Try / catch

try {
    runtimeService.trigger(executionId);
} catch (FlowableException e) {
    if (e.getMessage().contains("TriggerableActivityBehavior")) { /* use correct completion API */ }
    throw e;
}

Prevention

When it happens

Trigger: runtimeService.trigger(executionId) is called on an execution whose service task delegate class resolves to a non-triggerable ActivityBehavior (e.g. a plain JavaDelegate wrapped as non-triggerable, or behavior not implementing TriggerableActivityBehavior).

Common situations: Client code signals an execution that is waiting on a non-triggerable task; the delegate class was changed from an async/triggerable implementation to a plain one; BPMN model changes made the current wait state non-triggerable.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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