{"record":{"id":"d5ca7c450f51804e","repo":"flowable/flowable-engine","slug":"exception-while-invoking-tasklistener-e-getmess","errorCode":null,"errorMessage":"Exception while invoking TaskListener: ${e.getMessage()}","messagePattern":"Exception while invoking TaskListener: (.+?)","errorType":"exception","errorClass":"ActivitiException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/listener/DelegateExpressionTaskListener.java","lineNumber":53,"sourceCode":"    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        // Note: we can't cache the result of the expression, because the\n        // execution can change: eg. delegateExpression='${mySpringBeanFactory.randomSpringBean()}'\n        Object delegate = expression.getValue(delegateTask);\n        ClassDelegate.applyFieldDeclaration(fieldDeclarations, delegate);\n\n        if (delegate instanceof TaskListener) {\n            try {\n                Context.getProcessEngineConfiguration()\n                        .getDelegateInterceptor()\n                        .handleInvocation(new TaskListenerInvocation((TaskListener) delegate, delegateTask));\n            } catch (Exception e) {\n                throw new ActivitiException(\"Exception while invoking TaskListener: \" + e.getMessage(), e);\n            }\n        } else {\n            throw new ActivitiIllegalArgumentException(\"Delegate expression \" + expression\n                    + \" 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":35,"sourceCodeEnd":69,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/listener/DelegateExpressionTaskListener.java#L35-L69","documentation":"Thrown as ActivitiException from DelegateExpressionTaskListener.notify when the resolved delegate is a TaskListener but invoking it through the configured DelegateInterceptor (TaskListenerInvocation) throws an exception. The original exception's message is embedded and the cause is attached.","triggerScenarios":"A <activiti:taskListener event=\"...\" delegateExpression=\"${bean}\"/> resolves to a valid TaskListener, but during handleInvocation the listener's notify(DelegateTask) throws — e.g. NPE inside the listener, failed dependency injection, DB/service call failure inside the listener body.","commonSituations":"Listener code assuming injected fields/variables are non-null; listener calling an external service that fails; exceptions in Spring bean initialization during expression resolution; delegate interceptor wrapping adding behavior (transactions, security) that throws.","solutions":["Read the wrapped cause (e.getCause()) — the message here only repeats the inner exception's message.","Fix the exception inside the TaskListener implementation itself (null checks, error handling around external calls).","Check the delegate interceptor configuration for custom wrapping that might throw.","Add logging inside the listener to pinpoint the failing statement.","If the failure is environmental (DB, network), make the listener retry or degrade gracefully instead of throwing."],"exampleFix":"// before: listener body can NPE\npublic void notify(DelegateTask task) { task.getVariable(\"cfg\").toString(); }\n\n// after: guard\npublic void notify(DelegateTask task) {\n  Object cfg = task.getVariable(\"cfg\");\n  if (cfg != null) { cfg.toString(); }\n}","handlingStrategy":"try-catch","validationCode":"// pre-flight: resolve and dry-run the delegate where possible\nObject delegate = applicationContext.getBean(\"myTaskListener\");\nif (!(delegate instanceof TaskListener)) {\n    throw new IllegalStateException(\"myTaskListener is not a TaskListener\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    taskService.complete(taskId);\n} catch (ActivitiException e) {\n    if (e.getMessage().startsWith(\"Exception while invoking TaskListener\")) {\n        Throwable root = e;\n        while (root.getCause() != null) root = root.getCause();\n        logger.error(\"TaskListener failed: \", root);\n    }\n    throw e;\n}","preventionTips":["Unwrap getCause() chains — this error's message is only the inner exception's message.","Keep TaskListener bodies defensive: null-check variables and wrap external calls.","Avoid heavyweight logic (network, transactions) inside task listeners, or handle failures locally.","Unit-test listeners with a DelegateTask mock before process deployment."],"tags":["bpmn","task-listener","delegate-expression","wrapped-exception"],"backgroundTag":"upstream-api-error","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}