flowable/flowable-engine · error · FlowableIllegalArgumentException

Delegate expression + expression + did neither resolve to…

Error message

Delegate expression + expression + did neither resolve to an implementation of + ActivityBehavior.class + nor + JavaDelegate.class

What it means

ServiceTaskDelegateExpressionActivityBehavior.execute throws FlowableIllegalArgumentException when a service task's delegate expression resolves to an object that implements neither ActivityBehavior nor JavaDelegate. The delegate expression must produce one of these two supported types for Flowable to execute the task.

Solutions

  1. Make the delegate class implement JavaDelegate (or ActivityBehavior) and confirm the execute(DelegateExecution) method is public
  2. Verify the bean referenced by the delegate expression is of the intended type in the application context
  3. Check that AOP proxying does not strip the JavaDelegate interface (add interface-aware proxying or proxyTargetClass)
  4. Test the expression resolution in isolation: expression.getValue returns the bean; assert instanceof JavaDelegate

Example fix

// before
@Service("orderProcessor")
public class OrderProcessor { public void process(Order o) {...} }
// after
@Service("orderProcessor")
public class OrderProcessor implements JavaDelegate {
  public void execute(DelegateExecution execution) {...}
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify the bean the delegate expression resolves to implements JavaDelegate
Object bean = applicationContext.getBean("orderProcessor");
if (!(bean instanceof JavaDelegate) && !(bean instanceof ActivityBehavior)) {
    throw new IllegalStateException("Delegate bean must implement JavaDelegate or ActivityBehavior");
}

Type guard

public static boolean isValidDelegate(Object o) {
    return o instanceof JavaDelegate || o instanceof ActivityBehavior;
}

Try / catch

try {
    processEngine.getRuntimeService().startProcessInstanceByKey(processKey);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("did neither resolve to an implementation of")) {
        // fix bean type or expression reference
    }
}

Prevention

When it happens

Trigger: The expression `${someBean}` resolves to a bean in the Spring/CDI container that is not a JavaDelegate or ActivityBehavior — e.g. a plain service class, wrong type registered under the expected name, or a proxy losing the interface.

Common situations: Spring bean renamed or replaced with a different type; bean is a plain @Service without implements JavaDelegate; AOP proxies (e.g. @Transactional) hiding the interface from expression resolution; copy-paste of expression referencing the wrong bean.

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/918fbf1142e997a4. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/ServiceTaskDelegateExpressionActivityBehavior.java:205

                } else if (delegate instanceof FutureJavaDelegate) {
                    FutureJavaDelegate<Object> futureJavaDelegate = (FutureJavaDelegate<Object>) delegate;
                    DelegateInvocation invocation = new FutureJavaDelegateInvocation(futureJavaDelegate, execution,
                            processEngineConfiguration.getAsyncTaskInvoker());
                    processEngineConfiguration.getDelegateInterceptor().handleInvocation(invocation);

                    Object invocationResult = invocation.getInvocationResult();
                    if (invocationResult instanceof CompletableFuture) {
                        CompletableFuture<Object> future = (CompletableFuture<Object>) invocationResult;

                        CommandContextUtil.getAgenda(commandContext).planFutureOperation(future, new FutureJavaDelegateCompleteAction(futureJavaDelegate, execution, loggingSessionEnabled));
                    } else {
                        throw new FlowableIllegalStateException(
                                "Invocation result " + invocationResult + " from invocation " + invocation + " was not a CompletableFuture");
                    }


                } else {
                    throw new FlowableIllegalArgumentException("Delegate expression " + expression + " did neither resolve to an implementation of " + ActivityBehavior.class + " nor " + JavaDelegate.class);
                }

            } else {
                if (loggingSessionEnabled) {
                    BpmnLoggingSessionUtil.addLoggingData(LoggingSessionConstants.TYPE_SKIP_TASK, "Skipped service task " + execution.getCurrentActivityId() +
                            " with skip expression " + skipExpressionText, execution);
                }
                leave(execution);
            }
        } catch (Exception exc) {

            handleException(exc, execution, loggingSessionEnabled);

        }
    }

    protected void handleException(Throwable exc, DelegateExecution execution, boolean loggingSessionEnabled) {
        if (loggingSessionEnabled) {

View on GitHub (pinned to d6d39ce1c6)