flowable/flowable-engine · error · ActivitiIllegalArgumentException

doesn't implement nor

Error message

%s doesn't implement %s nor %s

What it means

ClassDelegate.getExecutionListenerInstance instantiates the configured delegate class and expects it to implement ExecutionListener or JavaDelegate. If the instantiated class implements neither, an ActivitiIllegalArgumentException is thrown naming the class.

Solutions

  1. Make the delegate class implement org.activiti.engine.delegate.ExecutionListener (or JavaDelegate)
  2. Correct the class attribute in the BPMN XML to point at the right class
  3. Ensure the deployed class version actually implements the interface (check for stale jars)

Example fix

// before
public class MyDelegate {
    public void run(DelegateExecution e) { ... }
}
// after
public class MyDelegate implements ExecutionListener {
    public void notify(DelegateExecution e) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = Class.forName(delegateClassName);
if (!ExecutionListener.class.isAssignableFrom(c) && !JavaDelegate.class.isAssignableFrom(c)) {
    throw new IllegalStateException(delegateClassName + " must implement ExecutionListener or JavaDelegate");
}

Type guard

static boolean isValidExecutionDelegate(Object o) {
    return o instanceof ExecutionListener || o instanceof JavaDelegate;
}

Try / catch

try {
    runtimeService.signal(executionId);
} catch (org.activiti.engine.ActivitiIllegalArgumentException e) {
    if (e.getMessage().contains("doesn't implement")) {
        // fix the delegate class in the service task definition
    }
}

Prevention

When it happens

Trigger: A service task or execution listener configured with class='com.example.MyDelegate' whose class implements neither ExecutionListener nor JavaDelegate, resolved during getExecutionListenerInstance at execution time.

Common situations: Wrong class name in the BPMN XML class attribute; refactoring removed the interface implementation; typo'd class pointing at an unrelated helper class.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/beac0f6aad5873f8. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/ClassDelegate.java:110

    // Execution listener
    @Override
    public void notify(DelegateExecution execution) {
        if (executionListenerInstance == null) {
            executionListenerInstance = getExecutionListenerInstance();
        }
        Context.getProcessEngineConfiguration()
                .getDelegateInterceptor()
                .handleInvocation(new ExecutionListenerInvocation(executionListenerInstance, execution));
    }

    protected ExecutionListener getExecutionListenerInstance() {
        Object delegateInstance = instantiateDelegate(className, fieldDeclarations);
        if (delegateInstance instanceof ExecutionListener) {
            return (ExecutionListener) delegateInstance;
        } else if (delegateInstance instanceof JavaDelegate) {
            return new ServiceTaskJavaDelegateActivityBehavior((JavaDelegate) delegateInstance, skipExpression);
        } else {
            throw new ActivitiIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + ExecutionListener.class + " nor " + JavaDelegate.class);
        }
    }

    // Task listener
    @Override
    public void notify(DelegateTask delegateTask) {
        if (taskListenerInstance == null) {
            taskListenerInstance = getTaskListenerInstance();
        }
        try {
            Context.getProcessEngineConfiguration()
                    .getDelegateInterceptor()
                    .handleInvocation(new TaskListenerInvocation(taskListenerInstance, delegateTask));
        } catch (Exception e) {
            throw new ActivitiException("Exception while invoking TaskListener: " + e.getMessage(), e);
        }
    }

View on GitHub (pinned to d6d39ce1c6)