{"record":{"id":"225384e1a18d6a6a","repo":"flowable/flowable-engine","slug":"cannot-trigger-execution-the-activitybehavior","errorCode":null,"errorMessage":"Cannot trigger ${execution} : the activityBehavior ${activityBehavior.getClass()} does not implement the org.flowable.engine.impl.delegate.TriggerableActivityBehavior interface","messagePattern":"Cannot trigger (.+?) : the activityBehavior (.+?) does not implement the org\\.flowable\\.engine\\.impl\\.delegate\\.TriggerableActivityBehavior interface","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/agenda/TriggerExecutionOperation.java","lineNumber":72,"sourceCode":"\n            ActivityBehavior activityBehavior = (ActivityBehavior) ((FlowNode) currentFlowElement).getBehavior();\n            if (activityBehavior instanceof TriggerableActivityBehavior) {\n\n                if (!triggerAsync) {\n                    ((TriggerableActivityBehavior) activityBehavior).trigger(execution, null, null);\n                    \n                } else {\n                    ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);\n                    JobService jobService = processEngineConfiguration.getJobServiceConfiguration().getJobService();\n                    JobEntity job = JobUtil.createJob(execution, currentFlowElement, AsyncTriggerJobHandler.TYPE, processEngineConfiguration);\n\n                    jobService.createAsyncJob(job, true);\n                    jobService.scheduleAsyncJob(job);\n                }\n\n\n            } else {\n                throw new FlowableException(\"Cannot trigger \" + execution\n                    + \" : the activityBehavior \" + activityBehavior.getClass() + \" does not implement the \"\n                    + TriggerableActivityBehavior.class.getName() + \" interface\");\n\n            }\n\n        } else if (currentFlowElement == null) {\n            throw new FlowableException(\"Cannot trigger \" + execution\n                    + \" : no current flow element found. Check the execution id that is being passed \"\n                    + \"(it should not be a process instance execution, but a child execution currently referencing a flow element).\");\n\n        } else {\n            throw new FlowableException(\"Programmatic error: cannot trigger \" + execution + \", invalid flow element type found: \"\n                    + currentFlowElement.getClass().getName() + \".\");\n\n        }\n    }\n\n}","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/agenda/TriggerExecutionOperation.java#L54-L90","documentation":"TriggerExecutionOperation.run resumes a waiting execution (e.g. after signal/message/trigger). The current flow element's behavior must implement TriggerableActivityBehavior to be triggered; if it does not, the engine cannot continue the execution and throws this FlowableException.","triggerScenarios":"Calling runtimeService.trigger(executionId) (or signal/message received) on an execution whose current activity behavior is not TriggerableActivityBehavior — e.g. triggering the wrong execution id, or an execution parked on a non-waiting element.","commonSituations":"Triggering an execution selected by the wrong query (not actually waiting at a receive task/user task); race conditions where the execution already moved on; custom behaviors not implementing the right interface.","solutions":["Query the execution and verify its activityId is a waiting state (receive task, intermediate catch event) before triggering","Ensure custom ActivityBehaviors implement TriggerableActivityBehavior when they must be triggerable","Guard against double-triggers with an optimistic-lock/race check","Use event subscription queries (signalEventReceived/messageEventReceived) instead of raw trigger when appropriate"],"exampleFix":"// before\nExecution e = runtimeService.createExecutionQuery().processInstanceId(pid).singleResult();\nruntimeService.trigger(e.getId());\n// after\nExecution e = runtimeService.createExecutionQuery()\n    .processInstanceId(pid)\n    .activityId(\"waitReceiveTask\")\n    .singleResult();\nif (e != null) {\n    runtimeService.trigger(e.getId());\n}","handlingStrategy":"validation","validationCode":"Execution e = runtimeService.createExecutionQuery()\n    .processInstanceId(pid)\n    .activityId(\"waitForSignal\")\n    .singleResult();\nif (e == null) {\n    throw new IllegalStateException(\"Execution not waiting at waitForSignal\");\n}\nruntimeService.trigger(e.getId());","typeGuard":"boolean isWaitingAtTriggerable(Execution e, String activityId) {\n    return e != null && activityId.equals(e.getActivityId());\n}","tryCatchPattern":"try {\n    runtimeService.trigger(executionId);\n} catch (FlowableException e) {\n    if (e.getMessage().contains(\"does not implement\") && e.getMessage().contains(\"TriggerableActivityBehavior\")) {\n        log.error(\"Execution {} is not at a triggerable activity; re-check query\", executionId);\n    }\n    throw e;\n}","preventionTips":["Query executions by activityId, not just processInstanceId","Handle idempotency for double-trigger races","Implement TriggerableActivityBehavior in custom waiting behaviors","Prefer signal/message-specific APIs over generic trigger"],"tags":["java","flowable","trigger","execution","behavior"],"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"}