{"record":{"id":"6e25fc103b28451f","repo":"flowable/flowable-engine","slug":"delegate-expression-expression-did-not-resolve-6e25fc","errorCode":null,"errorMessage":"Delegate expression ${expression} did not resolve to an implementation of ${TaskListener.class}","messagePattern":"Delegate expression (.+?) did not resolve to an implementation of (.+?)","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/listener/DelegateExpressionTaskListener.java","lineNumber":44,"sourceCode":" */\npublic class DelegateExpressionTaskListener implements TaskListener {\n\n    protected Expression expression;\n    protected List<FieldExtension> fieldExtensions;\n\n    public DelegateExpressionTaskListener(Expression expression, List<FieldExtension> fieldExtensions) {\n        this.expression = expression;\n        this.fieldExtensions = fieldExtensions;\n    }\n\n    @Override\n    public void notify(DelegateTask delegateTask) {\n        Object delegate = DelegateExpressionUtil.resolveDelegateExpression(expression, delegateTask, fieldExtensions);\n\n        if (delegate instanceof TaskListener taskListener) {\n            taskListener.notify(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.\n     */\n    public String getExpressionText() {\n        return expression.getExpressionText();\n    }\n\n}\n","sourceCodeStart":26,"sourceCodeEnd":56,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/listener/DelegateExpressionTaskListener.java#L26-L56","documentation":"DelegateExpressionTaskListener resolves a delegate expression against a DelegateTask and expects the result to implement TaskListener. When the resolved object is not a TaskListener it throws FlowableIllegalArgumentException. Same guard family as the case/plan-item delegate listeners, applied to task listeners.","triggerScenarios":"notify(delegateTask) resolves the expression and the object fails `instanceof TaskListener` — the expression points at a bean or value that is not a task listener.","commonSituations":"Spring bean exposed under the referenced name has the wrong type; a BPMN TaskListener (org.flowable.engine.delegate.TaskListener) is referenced where the CMMN TaskListener is required; expression typo returning a scalar.","solutions":["Make the delegate implement org.flowable.task.service.delegate.TaskListener (the CMMN one).","Verify you are not mixing the BPMN engine's TaskListener interface with the CMMN one — a very common cause.","Fix the expression to reference the correct bean name/type.","Add a unit test resolving each delegate expression and asserting the expected interface."],"exampleFix":"// before\npublic class MyListener implements org.flowable.engine.delegate.TaskListener { ... } // BPMN interface\n// after\npublic class MyListener implements org.flowable.task.service.delegate.TaskListener {\n    public void notify(DelegateTask delegateTask) { /* ... */ }\n}","handlingStrategy":"type-guard","validationCode":"Object delegate = DelegateExpressionUtil.resolveDelegateExpression(expression, delegateTask, null);\nif (!(delegate instanceof org.flowable.task.service.delegate.TaskListener)) {\n    throw new IllegalArgumentException(\"Expression must resolve to a CMMN TaskListener\");\n}","typeGuard":"boolean isCmmnTaskListener(Object o) {\n    return o instanceof org.flowable.task.service.delegate.TaskListener;\n}","tryCatchPattern":"try {\n    // task creation triggers listeners\n} catch (FlowableIllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"TaskListener\")) {\n        throw new ConfigurationException(\"Delegate for \" + expression + \" must implement the CMMN TaskListener\", e);\n    }\n    throw e;\n}","preventionTips":["Beware BPMN vs CMMN TaskListener interfaces with identical names — import carefully","Test delegate expression resolution for each listener in a unit test","Rename beans per engine module to avoid cross-wiring"],"tags":["flowable","cmmn","task-listener","delegate-expression","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"}