{"record":{"id":"04fe552f077e48fc","repo":"flowable/flowable-engine","slug":"completing-can-only-be-called-on-a-subprocessact","errorCode":null,"errorMessage":"completing() can only be called on a SubProcessActivityBehavior instance for + execution","messagePattern":"completing\\(\\) can only be called on a SubProcessActivityBehavior instance for \\+ execution","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java","lineNumber":256,"sourceCode":"                }\n            }\n        } else {\n            throw new FlowableException(\"signal() can only be called on a \" + TriggerableActivityBehavior.class.getName() + \" instance for \" + execution);\n        }\n    }\n\n    // Subprocess activityBehaviour\n\n    @Override\n    public void completing(DelegateExecution execution, DelegateExecution subProcessInstance) throws Exception {\n        if (activityBehaviorInstance == null) {\n            activityBehaviorInstance = getActivityBehaviorInstance();\n        }\n\n        if (activityBehaviorInstance instanceof SubProcessActivityBehavior) {\n            ((SubProcessActivityBehavior) activityBehaviorInstance).completing(execution, subProcessInstance);\n        } else {\n            throw new FlowableException(\"completing() can only be called on a \" + SubProcessActivityBehavior.class.getName() + \" instance for \" + execution);\n        }\n    }\n\n    @Override\n    public void completed(DelegateExecution execution) throws Exception {\n        if (activityBehaviorInstance == null) {\n            activityBehaviorInstance = getActivityBehaviorInstance();\n        }\n\n        if (activityBehaviorInstance instanceof SubProcessActivityBehavior) {\n            ((SubProcessActivityBehavior) activityBehaviorInstance).completed(execution);\n        } else {\n            throw new FlowableException(\"completed() can only be called on a \" + SubProcessActivityBehavior.class.getName() + \" instance for \" + execution);\n        }\n    }\n\n    protected ActivityBehavior getActivityBehaviorInstance() {\n        Object delegateInstance = instantiateDelegate(className, fieldDeclarations);","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java#L238-L274","documentation":"When a subprocess (typically an ad-hoc or custom subprocess) completes, ClassDelegate.completing() delegates to the resolved behavior only if it implements SubProcessActivityBehavior; otherwise a FlowableException is thrown. The completing()/completed() callbacks exist only for subprocess behaviors, so Flowable rejects calls routed through a non-subprocess delegate.","triggerScenarios":"The inner activity of a subprocess/service-task-as-subprocess uses a ClassDelegate whose resolved ActivityBehavior does not implement SubProcessActivityBehavior, and the engine (or code) invokes completing(execution, subProcessInstance) when the subprocess instance finishes.","commonSituations":"Custom subprocess configuration pointing at a plain ActivityBehavior; a delegate class changed to no longer extend AbstractBpmnActivityBehavior/SubProcessActivityBehavior; engine internals or custom code calling completing() on a normal service task delegate.","solutions":["Make the delegate's ActivityBehavior implement (or extend AbstractBpmnActivityBehavior to gain) SubProcessActivityBehavior.","Verify the class configured on the subprocess element is actually a subprocess behavior (e.g. extends SubProcessActivityBehavior).","Ensure custom code only calls completing()/completed() for elements configured as subprocess behaviors.","Restore the previous delegate class if a refactoring replaced a SubProcessActivityBehavior implementation."],"exampleFix":"// before\npublic class MyBehavior implements ActivityBehavior { ... }\n// after\npublic class MyBehavior extends AbstractBpmnActivityBehavior {\n    @Override public void completing(DelegateExecution execution, ExecutionContext subProcessInstance) { ... }\n}","handlingStrategy":"type-guard","validationCode":"if (!(behavior instanceof SubProcessActivityBehavior)) throw new IllegalStateException(\"Delegate must be a SubProcessActivityBehavior\");","typeGuard":"boolean isSubProcessBehavior(ActivityBehavior b) { return b instanceof SubProcessActivityBehavior; }","tryCatchPattern":"try {\n    runtimeService.startProcessInstanceByKey(\"proc\");\n} catch (FlowableException e) {\n    if (e.getMessage().contains(\"completing() can only be called\")) { /* fix delegate class */ }\n    throw e;\n}","preventionTips":["Extend AbstractBpmnActivityBehavior for subprocess delegates.","Avoid calling internal completing()/completed() from application code.","Keep subprocess delegate classes dedicated, not shared with plain tasks."],"tags":["flowable","delegate","subprocess","unsupported-operation"],"backgroundTag":"unsupported-operation","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"}