{"record":{"id":"07a18052cbf3ef5f","repo":"flowable/flowable-engine","slug":"completed-can-only-be-called-on-a-s-instance","errorCode":null,"errorMessage":"completed() can only be called on a %s instance","messagePattern":"completed\\(\\) can only be called on a (.+?) instance","errorType":"exception","errorClass":"ActivitiException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/ClassDelegate.java","lineNumber":206,"sourceCode":"        }\n\n        if (activityBehaviorInstance instanceof SubProcessActivityBehavior) {\n            ((SubProcessActivityBehavior) activityBehaviorInstance).completing(execution, subProcessInstance);\n        } else {\n            throw new ActivitiException(\"completing() can only be called on a \" + SubProcessActivityBehavior.class.getName() + \" instance\");\n        }\n    }\n\n    @Override\n    public void completed(ActivityExecution execution) throws Exception {\n        if (activityBehaviorInstance == null) {\n            activityBehaviorInstance = getActivityBehaviorInstance(execution);\n        }\n\n        if (activityBehaviorInstance instanceof SubProcessActivityBehavior) {\n            ((SubProcessActivityBehavior) activityBehaviorInstance).completed(execution);\n        } else {\n            throw new ActivitiException(\"completed() can only be called on a \" + SubProcessActivityBehavior.class.getName() + \" instance\");\n        }\n    }\n\n    protected ActivityBehavior getActivityBehaviorInstance(ActivityExecution execution) {\n        Object delegateInstance = instantiateDelegate(className, fieldDeclarations);\n\n        if (delegateInstance instanceof ActivityBehavior) {\n            return determineBehaviour((ActivityBehavior) delegateInstance, execution);\n        } else if (delegateInstance instanceof JavaDelegate) {\n            return determineBehaviour(new ServiceTaskJavaDelegateActivityBehavior((JavaDelegate) delegateInstance, skipExpression), execution);\n        } else {\n            throw new ActivitiIllegalArgumentException(delegateInstance.getClass().getName() + \" doesn't implement \" + JavaDelegate.class.getName() + \" nor \" + ActivityBehavior.class.getName());\n        }\n    }\n\n    // Adds properties to the given delegation instance (eg multi instance) if needed\n    protected ActivityBehavior determineBehaviour(ActivityBehavior delegateInstance, ActivityExecution execution) {\n        if (hasMultiInstanceCharacteristics()) {","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/ClassDelegate.java#L188-L224","documentation":"completed() is the second half of the SubProcessActivityBehavior contract: it is called after the subprocess instance has finished. ClassDelegate checks the resolved delegate implements SubProcessActivityBehavior before casting; otherwise it throws this ActivitiException naming the required interface.","triggerScenarios":"A subprocess ends and the engine calls completed(execution) on the ClassDelegate, whose resolved delegate instance is not a SubProcessActivityBehavior (e.g. it only implements ActivityBehavior or JavaDelegate).","commonSituations":"Same root cause as the completing() error: wrong delegate class configured for a subprocess activity; the delegate was replaced during deployment with an incompatible one; runtime reload picks up a different implementation.","solutions":["Make the delegate class implement SubProcessActivityBehavior including completed(ActivityExecution).","Fix the className on the ClassDelegate (or the classpath resource) so the intended SubProcessActivityBehavior implementation is instantiated.","Review recent deployments/jars for a duplicate or stale class shadowing the correct implementation."],"exampleFix":"// before\npublic class SubDelegate implements JavaDelegate {\n  public void execute(DelegateExecution e) { ... }\n}\n// after\npublic class SubDelegate implements SubProcessActivityBehavior {\n  public void completed(ActivityExecution execution) { ... }\n  public void completing(ActivityExecution execution, ActivityExecution subProcessInstance) { ... }\n}","handlingStrategy":"validation","validationCode":"Class<?> clazz = Class.forName(delegateClassName);\nif (!SubProcessActivityBehavior.class.isAssignableFrom(clazz)) {\n  throw new IllegalStateException(delegateClassName + \" must implement SubProcessActivityBehavior\");\n}","typeGuard":"boolean handlesSubProcessCompletion(Object delegate) { return delegate instanceof SubProcessActivityBehavior; }","tryCatchPattern":"try {\n  classDelegate.completed(execution);\n} catch (ActivitiException e) {\n  if (e.getMessage().contains(\"SubProcessActivityBehavior\")) {\n    log.error(\"Subprocess completion delegate misconfigured\", e);\n  } else throw e;\n}","preventionTips":["Implement both completing() and completed() together when writing SubProcessActivityBehavior delegates","Add integration tests that run subprocesses to completion with each delegate","Avoid reusing plain service-task delegates on subprocess boundary activities"],"tags":["delegate","subprocess","bpmn","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-14T11:17:12.474Z"}