flowable/flowable-engine · error · FlowableIllegalArgumentException

Delegate expression " + expression + " did neither resolve…

Error message

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

What it means

Thrown when a delegate expression in the migration document resolves to an object that implements neither ActivityBehavior nor JavaDelegate. Flowable's migration path executes migrated activity instances' delegate expressions via the delegate interceptor, which requires one of those two types. The check happens at migration execution time inside ProcessInstanceMigrationManagerImpl.

Solutions

  1. Change the expression target object so it implements JavaDelegate or ActivityBehavior
  2. Fix the process variable so it stores a JavaDelegate/ActivityBehavior instance before migrating
  3. Correct the delegate expression string in the process definition to point at the right bean/class
  4. Prefer class-based delegates (flowable:class) instead of delegate expressions to avoid type resolution issues

Example fix

// before
public class MyTask { public void execute() {} } // expression ${myTask} resolves to wrong type
// after
public class MyTask implements JavaDelegate { public void execute(DelegateExecution e) {} }
Defensive patterns

Strategy: type-guard

Validate before calling

Object d = DelegateExpressionUtil.resolveDelegateExpression(expr, processInstance, Collections.emptyList());
if (!(d instanceof JavaDelegate) && !(d instanceof ActivityBehavior)) {
    throw new IllegalStateException("Delegate expression resolves to non-delegate type: " + d.getClass());
}

Type guard

boolean isUsableDelegate(Object o) {
    return o instanceof JavaDelegate || o instanceof ActivityBehavior;
}

Try / catch

try {
    migrationBuilder.migrate(instanceId);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("Delegate expression")) {
        // fix the variable/bean type, then retry
    }
}

Prevention

When it happens

Trigger: Migrating a process instance to a new definition whose activity carries a delegate expression that resolves (via expression resolution against process instance variables) to a plain object, String, bean method result, or other non-delegate type.

Common situations: A process variable referenced by the delegate expression was changed (or removed/re-added) so it no longer holds a JavaDelegate/ActivityBehavior; the expression points to a Spring bean of the wrong type; a refactored class no longer implements JavaDelegate; expression typo returning a String.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/migration/ProcessInstanceMigrationManagerImpl.java:620

            String preUpgradeJavaDelegate, CommandContext commandContext) {
        
        CommandContextUtil.getProcessEngineConfiguration(commandContext).getDelegateInterceptor()
            .handleInvocation(new JavaDelegateInvocation((JavaDelegate) defaultInstantiateDelegate(preUpgradeJavaDelegate, Collections.emptyList()),
                (ExecutionEntityImpl) processInstance));
    }

    protected void executeExpression(ProcessInstance processInstance, ProcessDefinition procDefToMigrateTo, 
            String preUpgradeJavaDelegateExpression, CommandContext commandContext) {
        
        Expression expression = CommandContextUtil.getProcessEngineConfiguration(commandContext).getExpressionManager().createExpression(preUpgradeJavaDelegateExpression);

        Object delegate = DelegateExpressionUtil.resolveDelegateExpression(expression, (VariableContainer) processInstance, Collections.emptyList());
        if (delegate instanceof ActivityBehavior) {
            CommandContextUtil.getProcessEngineConfiguration(commandContext).getDelegateInterceptor().handleInvocation(new ActivityBehaviorInvocation((ActivityBehavior) delegate, (ExecutionEntityImpl) processInstance));
        } else if (delegate instanceof JavaDelegate) {
            CommandContextUtil.getProcessEngineConfiguration(commandContext).getDelegateInterceptor().handleInvocation(new JavaDelegateInvocation((JavaDelegate) delegate, (ExecutionEntityImpl) processInstance));
        } else {
            throw new FlowableIllegalArgumentException("Delegate expression " + expression + " did neither resolve to an implementation of " + ActivityBehavior.class + " nor " + JavaDelegate.class);
        }
    }

    protected List<ChangeActivityStateBuilderImpl> prepareChangeStateBuilders(ExecutionEntity processInstanceExecution, ProcessDefinition procDefToMigrateTo, ProcessInstanceMigrationDocument document, CommandContext commandContext) {
        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);

        // Check processDefinition tenant
        String procDefTenantId = procDefToMigrateTo.getTenantId();
        if (!isSameOrDefaultTenant(processInstanceExecution.getTenantId(), procDefToMigrateTo.getKey(), 
                procDefTenantId, CommandContextUtil.getProcessEngineConfiguration(commandContext))) {
            
            throw new FlowableException("Tenant mismatch between Process Instance ('" + processInstanceExecution.getTenantId() + "') and Process Definition ('" + procDefTenantId + "') to migrate to");
        }

        List<ChangeActivityStateBuilderImpl> changeActivityStateBuilders = new ArrayList<>();
        ChangeActivityStateBuilderImpl mainProcessChangeActivityStateBuilder = new ChangeActivityStateBuilderImpl();
        mainProcessChangeActivityStateBuilder.processInstanceId(processInstanceExecution.getId());
        changeActivityStateBuilders.add(mainProcessChangeActivityStateBuilder);

View on GitHub (pinned to d6d39ce1c6)