{"record":{"id":"3094a81b512afe6f","repo":"flowable/flowable-engine","slug":"signal-can-only-be-called-on-a-triggerableactivi","errorCode":null,"errorMessage":"signal() can only be called on a TriggerableActivityBehavior instance for + execution","messagePattern":"signal\\(\\) can only be called on a TriggerableActivityBehavior instance for \\+ execution","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java","lineNumber":241,"sourceCode":"                if (!ErrorPropagation.mapException(e, (ExecutionEntity) execution, mapExceptions)) {\n                    throw e;\n                }\n            }\n        } else if (activityBehaviorInstance instanceof TriggerableActivityBehavior) {\n            try {\n                ((TriggerableActivityBehavior) activityBehaviorInstance).trigger(execution, signalName, signalData);\n                if (triggerable) {\n                    leave(execution);\n                }\n            } catch (BusinessError error) {\n                ErrorPropagation.propagateError(error, execution);\n            } catch (RuntimeException e) {\n                if (!ErrorPropagation.mapException(e, (ExecutionEntity) execution, mapExceptions)) {\n                    throw e;\n                }\n            }\n        } else {\n            throw new FlowableException(\"signal() can only be called on a \" + TriggerableActivityBehavior.class.getName() + \" instance for \" + execution);\n        }\n    }\n\n    // Subprocess activityBehaviour\n\n    @Override\n    public void completing(DelegateExecution execution, DelegateExecution subProcessInstance) throws Exception {\n        if (activityBehaviorInstance == null) {\n            activityBehaviorInstance = getActivityBehaviorInstance();\n        }\n\n        if (activityBehaviorInstance instanceof SubProcessActivityBehavior) {\n            ((SubProcessActivityBehavior) activityBehaviorInstance).completing(execution, subProcessInstance);\n        } else {\n            throw new FlowableException(\"completing() can only be called on a \" + SubProcessActivityBehavior.class.getName() + \" instance for \" + execution);\n        }\n    }\n","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java#L223-L259","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Only call runtimeService.trigger() on executions whose current behavior implements TriggerableActivityBehavior; check the wait state first.","Make the delegate's ActivityBehavior implement TriggerableActivityBehavior (signal method) if it should accept signals.","Implement the delegate as a JavaDelegate with triggerable=true (ServiceTaskJavaDelegateActivityBehavior with triggerable) so signal support is wired.","Fix process design: replace the signal with the correct completion path (e.g. complete the user task or use a message/signal event)."],"exampleFix":"// before\nexecutionEntity.trigger(); // works for any wait state\n// after\nif (executionEntity.getCurrentFlowElement() instanceof ServiceTask\n        && behavior instanceof TriggerableActivityBehavior) {\n    executionEntity.trigger();\n} else {\n    // use the appropriate completion API for this wait state\n}","handlingStrategy":"type-guard","validationCode":"Execution exec = runtimeService.createExecutionQuery().executionId(id).singleResult();\n// only trigger executions waiting on a triggerable activity","typeGuard":"boolean canTrigger(ActivityBehavior b) { return b instanceof TriggerableActivityBehavior; }","tryCatchPattern":"try {\n    runtimeService.trigger(executionId);\n} catch (FlowableException e) {\n    if (e.getMessage().contains(\"TriggerableActivityBehavior\")) { /* use correct completion API */ }\n    throw e;\n}","preventionTips":["Check the current wait state's behavior before signaling.","Set triggerable=true on service tasks that must accept signals.","Model signal reception with proper intermediate catching events."],"tags":["flowable","delegate","signal","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}