{"record":{"id":"325058e19e933a92","repo":"flowable/flowable-engine","slug":"exception-while-invoking-tasklistener","errorCode":null,"errorMessage":"Exception while invoking TaskListener: ","messagePattern":"Exception while invoking TaskListener: ","errorType":"exception","errorClass":"ActivitiException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/persistence/entity/TaskEntity.java","lineNumber":777,"sourceCode":"        this.formKey = formKey;\n    }\n\n    public void fireEvent(String taskEventName) {\n        TaskDefinition taskDefinition = getTaskDefinition();\n        if (taskDefinition != null) {\n            List<TaskListener> taskEventListeners = getTaskDefinition().getTaskListener(taskEventName);\n            if (taskEventListeners != null) {\n                for (TaskListener taskListener : taskEventListeners) {\n                    ExecutionEntity execution = getExecution();\n                    if (execution != null) {\n                        setEventName(taskEventName);\n                    }\n                    try {\n                        Context.getProcessEngineConfiguration()\n                                .getDelegateInterceptor()\n                                .handleInvocation(new TaskListenerInvocation(taskListener, (DelegateTask) this));\n                    } catch (Exception e) {\n                        throw new ActivitiException(\"Exception while invoking TaskListener: \" + e.getMessage(), e);\n                    }\n                }\n            }\n        }\n    }\n\n    @Override\n    protected boolean isActivityIdUsedForDetails() {\n        return false;\n    }\n\n    // Override from VariableScopeImpl\n\n    // Overridden to avoid fetching *all* variables (as is the case in the super call)\n    @Override\n    protected VariableInstanceEntity getSpecificVariable(String variableName) {\n        CommandContext commandContext = Context.getCommandContext();\n        if (commandContext == null) {","sourceCodeStart":759,"sourceCodeEnd":795,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/persistence/entity/TaskEntity.java#L759-L795","documentation":"Wraps any Exception raised while invoking a registered TaskListener during task events (create/complete/assignment etc.). The engine routes the listener through the configured DelegateInterceptor; if the listener's notify() throws, it is rethrown as an ActivitiException with the delegate's message. The original exception is kept as the cause, so the real failure is in your listener code.","triggerScenarios":"A custom TaskListener (class, expression, or delegateExpression) throws any exception during fireEvent(TaskListener.EVENTNAME_*) — typically on task creation, completion, or assignment inside TaskEntity.","commonSituations":"NullPointerException inside listener code; listener delegateExpression points to a bean that fails to resolve; listener calls engine APIs that themselves fail; classpath issues loading the listener class; the DelegateInterceptor throws (e.g. custom security interceptor).","solutions":["Inspect the cause (getCause()) of this exception — the real bug is inside your TaskListener's notify() method","Fix or add error handling/logging in the listener implementation before it rethrows","Verify any delegateExpression beans exist and are injectable in the current context","Test the listener logic in isolation with a unit test calling notify(DelegateTask)"],"exampleFix":"// before: listener that throws\npublic void notify(DelegateTask task) {\n    String val = (String) task.getVariable(\"missing\"); // NPE risk\n    doWork(val.toLowerCase());\n}\n// after: defensive listener\npublic void notify(DelegateTask task) {\n    Object val = task.getVariable(\"missing\");\n    if (val == null) { LOG.warn(\"variable missing, skipping\"); return; }\n    doWork(val.toString().toLowerCase());\n}","handlingStrategy":"try-catch","validationCode":"// verify listener bean/expr resolves before deploy\nObject bean = applicationContext.getBean(listenerBeanName); // throws early if missing","typeGuard":null,"tryCatchPattern":"try {\n    taskService.complete(taskId);\n} catch (ActivitiException e) {\n    Throwable root = e; while (root.getCause() != null) root = root.getCause();\n    LOG.error(\"TaskListener failed: \" + root.getMessage(), root);\n}","preventionTips":["Write defensive listeners: null-check variables, never rethrow raw exceptions","Unit-test every TaskListener's notify() in isolation","Log and swallow non-fatal listener errors inside the listener itself","Verify delegateExpression beans exist for every deployment environment"],"tags":["listener","task","callback","reflection"],"backgroundTag":"listener-invocation-failed","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"}