{"record":{"id":"bbb8dc6ae15e6642","repo":"flowable/flowable-engine","slug":"delegateinstance-getclass-getname-doesn-t-i-bbb8dc","errorCode":null,"errorMessage":"${delegateInstance.getClass().getName()} doesn't implement ${CaseInstanceLifecycleListener.class}","messagePattern":"(.+?) doesn't implement (.+?)","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java","lineNumber":146,"sourceCode":"    }\n\n    protected PlanItemInstanceLifecycleListener getPlanItemLifeCycleListenerInstance() {\n        Object delegateInstance = instantiate(className);\n        applyFieldExtensions(fieldExtensions, delegateInstance, false);\n        if (delegateInstance instanceof PlanItemInstanceLifecycleListener) {\n            return (PlanItemInstanceLifecycleListener) delegateInstance;\n        } else {\n            throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + \" doesn't implement \" + PlanItemInstanceLifecycleListener.class);\n        }\n    }\n\n    protected CaseInstanceLifecycleListener getCaseLifeCycleListenerInstance() {\n        Object delegateInstance = instantiate(className);\n        applyFieldExtensions(fieldExtensions, delegateInstance, false);\n        if (delegateInstance instanceof CaseInstanceLifecycleListener) {\n            return (CaseInstanceLifecycleListener) delegateInstance;\n        } else {\n            throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + \" doesn't implement \" + CaseInstanceLifecycleListener.class);\n        }\n    }\n\n    @Override\n    public Object aggregateSingleVariable(DelegatePlanItemInstance planItemInstance, PlanItemVariableAggregatorContext context) {\n        return getPlanItemVariableAggregator().aggregateSingleVariable(planItemInstance, context);\n    }\n\n    @Override\n    public Object aggregateMultiVariables(DelegatePlanItemInstance planItemInstance, List<? extends VariableInstance> instances, PlanItemVariableAggregatorContext context) {\n        return getPlanItemVariableAggregator().aggregateMultiVariables(planItemInstance, instances, context);\n    }\n\n    protected PlanItemVariableAggregator getPlanItemVariableAggregator() {\n        Object delegateInstance = instantiate(className);\n        applyFieldExtensions(fieldExtensions, delegateInstance, false);\n        if (delegateInstance instanceof PlanItemVariableAggregator) {\n            return (PlanItemVariableAggregator) delegateInstance;","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java#L128-L164","documentation":"Case-level lifecycle listeners configured with flowable:class are resolved by getCaseLifeCycleListenerInstance, which requires the class to implement CaseInstanceLifecycleListener. If the instantiated object does not, this FlowableIllegalArgumentException is thrown.","triggerScenarios":"A case definition declares a case instance lifecycle listener via flowable:class; on first use (caseLifeCycleListenerInstance, typically when a case state changes) the class is instantiated and fails the instanceof check.","commonSituations":"Pointing the case listener attribute at a PlanItemInstanceLifecycleListener or other delegate class; refactoring moved the interface; copy/paste of class references between plan-item and case-level listener configs.","solutions":["Implement org.flowable.cmmn.api.listener.CaseInstanceLifecycleListener on the referenced class.","If the class handles plan item state changes, reference it where a plan-item lifecycle listener is expected instead.","Verify the fully-qualified name and that the deployed artifact contains the interface implementation.","Align the listener's getSourceState/getTargetState implementation with the case states you want to observe."],"exampleFix":"// before\npublic class CaseAuditListener implements PlanItemInstanceLifecycleListener { ... }\n// after\npublic class CaseAuditListener implements CaseInstanceLifecycleListener {\n  public String getSourceState() { return null; }\n  public String getTargetState() { return null; }\n  public void stateChanged(CaseInstance caseInstance, String oldState, String newState) { ... }\n}","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(className);\nif (!org.flowable.cmmn.api.listener.CaseInstanceLifecycleListener.class.isAssignableFrom(c)) {\n    throw new IllegalStateException(className + \" must implement CaseInstanceLifecycleListener\");\n}","typeGuard":"boolean isCaseLifecycleListener(Object o) { return o instanceof org.flowable.cmmn.api.listener.CaseInstanceLifecycleListener; }","tryCatchPattern":"try {\n    caseListener.stateChanged(caseInstance, oldState, newState);\n} catch (org.flowable.common.engine.api.FlowableIllegalArgumentException e) {\n    if (e.getMessage().contains(\"CaseInstanceLifecycleListener\")) { log.error(\"Not a case lifecycle listener: {}\", e.getMessage()); }\n    throw e;\n}","preventionTips":["Keep case-level and plan-item-level listener classes in clearly named packages/classes.","Validate all listener class references in case XML during CI.","Check the error message's interface name — it names exactly what must be implemented."],"tags":["java","cmmn","listener","flowable"],"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"}