{"record":{"id":"301a5b2155fc17ef","repo":"flowable/flowable-engine","slug":"delegate-expression-expression-did-not-res-301a5b","errorCode":null,"errorMessage":"Delegate expression \" + expression + \" did not resolve to an implementation of \" + TaskListener.class","messagePattern":"Delegate expression \" \\+ expression \\+ \" did not resolve to an implementation of \" \\+ TaskListener\\.class","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/listener/DelegateExpressionTaskListener.java","lineNumber":45,"sourceCode":" * @author Joram Barrez\n */\npublic class DelegateExpressionTaskListener implements TaskListener {\n\n    protected Expression expression;\n    private final List<FieldDeclaration> fieldDeclarations;\n\n    public DelegateExpressionTaskListener(Expression expression, List<FieldDeclaration> fieldDeclarations) {\n        this.expression = expression;\n        this.fieldDeclarations = fieldDeclarations;\n    }\n\n    @Override\n    public void notify(DelegateTask delegateTask) {\n        Object delegate = DelegateExpressionUtil.resolveDelegateExpression(expression, delegateTask, fieldDeclarations);\n        if (delegate instanceof TaskListener) {\n            CommandContextUtil.getProcessEngineConfiguration().getDelegateInterceptor().handleInvocation(new TaskListenerInvocation((TaskListener) delegate, delegateTask));\n        } else {\n            throw new FlowableIllegalArgumentException(\"Delegate expression \" + expression + \" did not resolve to an implementation of \" + TaskListener.class);\n        }\n    }\n\n    /**\n     * returns the expression text for this task listener. Comes in handy if you want to check which listeners you already have.\n     */\n    public String getExpressionText() {\n        return expression.getExpressionText();\n    }\n\n}\n","sourceCodeStart":27,"sourceCodeEnd":57,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/listener/DelegateExpressionTaskListener.java#L27-L57","documentation":"DelegateExpressionTaskListener resolves the task listener's delegate expression when a task event fires and requires the resolved object to implement TaskListener. Any other type causes notify to throw FlowableIllegalArgumentException. This is the task-scoped counterpart of the execution-listener type check.","triggerScenarios":"A user task declares <flowable:taskListener event=\"create\" delegateExpression=\"${someBean}\"/>; the bean the expression resolves to does not implement org.flowable.engine.delegate.TaskListener.","commonSituations":"Bean implements ExecutionListener or JavaDelegate but was attached as a task listener; class implements the old org.activiti TaskListener after migration; expression typo or duplicate bean name resolving to the wrong bean; Spring proxy masking the interface.","solutions":["Make the delegate bean implement org.flowable.engine.delegate.TaskListener and its notify(DelegateTask) method.","Fix the delegateExpression value so it resolves to a genuine TaskListener bean.","If the bean was written as an ExecutionListener, move it to the execution-listener slot or adapt it to TaskListener.","Check imports: TaskListener must be org.flowable.engine.delegate.TaskListener, not a legacy/Activiti one."],"exampleFix":"// before\npublic class AssignMe {\n  public void onCreate(DelegateTask t) { } // plain POJO, not a TaskListener\n}\n// after\npublic class AssignMe implements TaskListener {\n  @Override\n  public void notify(DelegateTask delegateTask) { ... }\n}","handlingStrategy":"validation","validationCode":"Object bean = applicationContext.getBean(\"myTaskListener\");\nif (!(bean instanceof org.flowable.engine.delegate.TaskListener)) {\n    throw new IllegalStateException(\"myTaskListener must implement TaskListener\");\n}","typeGuard":"public static boolean isTaskListener(Object o) {\n    return o instanceof org.flowable.engine.delegate.TaskListener;\n}","tryCatchPattern":"try {\n    taskListener.notify(delegateTask);\n} catch (org.flowable.common.engine.api.FlowableIllegalArgumentException e) {\n    log.error(\"Task listener delegateExpression resolved to a non-TaskListener: {}\", e.getMessage());\n    throw new IllegalArgumentException(\"Fix taskListener delegateExpression\", e);\n}","preventionTips":["Match listener kinds to element kinds: TaskListener only on user tasks, ExecutionListener on flows/elements.","Import org.flowable.engine.delegate.TaskListener, not legacy Activiti equivalents.","Unit-test each task listener bean with a DelegateTask fixture to catch interface drift early.","Validate all delegate expressions in BPMN XML at deployment time with a custom deploy validator."],"tags":["flowable","bpmn","delegate-expression","task-listener","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}