flowable/flowable-engine · error · ActivitiException

Error while invoking '%s' on class %s

Error message

Error while invoking '%s' on class %s

What it means

ClassDelegateUtil.applyFieldDeclaration is the shared utility performing the same setter-based injection as ClassDelegate: it invokes the matched setter reflectively and wraps IllegalArgumentException from Method.invoke into an ActivitiException ('Error while invoking ...'). It indicates the declared field value cannot legally be passed to the setter.

Source

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

    }

    public static void applyFieldDeclaration(List<FieldDeclaration> fieldDeclarations, Object target) {
        if (fieldDeclarations != null) {
            for (FieldDeclaration declaration : fieldDeclarations) {
                applyFieldDeclaration(declaration, target);
            }
        }
    }

    public static void applyFieldDeclaration(FieldDeclaration declaration, Object target) {
        Method setterMethod = ReflectUtil.getSetter(declaration.getName(),
                target.getClass(), declaration.getValue().getClass());

        if (setterMethod != null) {
            try {
                setterMethod.invoke(target, declaration.getValue());
            } catch (IllegalArgumentException e) {
                throw new ActivitiException("Error while invoking '" + declaration.getName() + "' on class " + target.getClass().getName(), e);
            } catch (IllegalAccessException e) {
                throw new ActivitiException("Illegal access when calling '" + declaration.getName() + "' on class " + target.getClass().getName(), e);
            } catch (InvocationTargetException e) {
                throw new ActivitiException("Exception while invoking '" + declaration.getName() + "' on class " + target.getClass().getName(), e);
            }
        } else {
            Field field = ReflectUtil.getField(declaration.getName(), target);
            if (field == null) {
                throw new ActivitiIllegalArgumentException("Field definition uses unexisting field '" + declaration.getName() + "' on class " + target.getClass().getName());
            }
            // Check if the delegate field's type is correct
            if (!fieldTypeCompatible(declaration, field)) {
                throw new ActivitiIllegalArgumentException("Incompatible type set on field declaration '" + declaration.getName()
                        + "' for class " + target.getClass().getName()
                        + ". Declared value has type " + declaration.getValue().getClass().getName()
                        + ", while expecting " + field.getType().getName());
            }
            ReflectUtil.setField(field, target, declaration.getValue());

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Match the declared value type to the setter parameter type in the process definition.
  2. Change the setter to accept a compatible type (String/Expression/Object) and convert internally.
  3. Inspect the wrapped cause to pinpoint the parameter conversion failure.

Example fix

// before
public void setThreshold(Expression threshold) { ... } // declared value is a plain String
// after
public void setThreshold(Object threshold) {
  this.threshold = threshold instanceof Expression e ? e : new FixedValue((String) threshold);
}
Defensive patterns

Strategy: validation

Validate before calling

Method m = target.getClass().getMethod("set" + capitalize(declaration.getName()), declaration.getValue().getClass());
// ensure a setter with exactly this parameter type exists before injection

Type guard

boolean setterCompatible(Object target, String field, Object value) {
  try {
    target.getClass().getMethod("set" + Character.toUpperCase(field.charAt(0)) + field.substring(1), value.getClass());
    return true;
  } catch (NoSuchMethodException e) { return false; }
}

Try / catch

try {
  ClassDelegateUtil.applyFieldDeclaration(declaration, target, throwExceptionOnMissingField);
} catch (ActivitiException e) {
  if (e.getMessage().startsWith("Error while invoking")) {
    log.error("Cannot inject field '{}' on {}: type mismatch", declaration.getName(), target.getClass(), e);
  } else throw e;
}

Prevention

When it happens

Trigger: A delegate (via ClassDelegateUtil-based helpers) receives a field declaration whose value type is incompatible with the setter's parameter type, making setterMethod.invoke(target, value) throw IllegalArgumentException.

Common situations: Same as 4394 but via the utility path: incompatible activiti:field value types (String vs int/Expression/Date), refactored setter signatures, EL expression producing an unexpected runtime type.

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/212923607e2fc8ed. Report an issue: GitHub.