flowable/flowable-engine · error · FlowableIllegalArgumentException
Incompatible type set on field declaration '<fieldName>' for
Error message
Incompatible type set on field declaration '<fieldName>' for class <className>. Declared value has type <declaredType>, while expecting <expectedType>
What it means
Thrown by ClassDelegateUtil.applyFieldDeclaration as a FlowableIllegalArgumentException when the injected value's Java type is not compatible with the declared field's type (fieldTypeCompatible returns false). The message states both the declared value type and the expected field type.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegateUtil.java:68
if (setterMethod != null) {
try {
setterMethod.invoke(target, declaration.getValue());
} catch (IllegalArgumentException e) {
throw new FlowableException("Error while invoking '" + declaration.getName() + "' on class " + target.getClass().getName(), e);
} catch (IllegalAccessException e) {
throw new FlowableException("Illegal access when calling '" + declaration.getName() + "' on class " + target.getClass().getName(), e);
} catch (InvocationTargetException e) {
throw new FlowableException("Exception while invoking '" + declaration.getName() + "' on class " + target.getClass().getName(), e);
}
} else {
Field field = ReflectUtil.getField(declaration.getName(), target);
if (field == null) {
throw new FlowableIllegalArgumentException("Field definition uses non-existing field '" + declaration.getName() + "' on class " + target.getClass().getName());
}
// Check if the delegate field's type is correct
if (!fieldTypeCompatible(declaration, field)) {
throw new FlowableIllegalArgumentException("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());
}
}
public static boolean fieldTypeCompatible(FieldDeclaration declaration, Field field) {
if (declaration.getValue() != null) {
return field.getType().isAssignableFrom(declaration.getValue().getClass());
} else {
// Null can be set any field type
return true;
}
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Align the BPMN field declaration type with the delegate field type (use the correct stringValue/expression element)
- Change the delegate field type to accept the injected value (e.g. String, or a type with a matching converter)
- Use <flowable:field><flowable:value> with a serialized/custom value matching the field type
- Add an explicit type check or conversion in the delegate's setter
Example fix
// before (field is int timeout) <flowable:field name="timeout" stringValue="10"/> // after <flowable:field name="timeout"><flowable:value>10</flowable:value></flowable:field> // or change delegate field to String timeout
Defensive patterns
Strategy: validation
Validate before calling
Field f = delegateClass.getDeclaredField(fieldName);
Object v = resolveDeclaredValue(declaration);
if (v != null && !f.getType().isAssignableFrom(v.getClass())) {
throw new ConfigException("Field " + fieldName + " expects " + f.getType() + " but got " + v.getClass());
} Type guard
static boolean fieldTypeOk(Class<?> delegate, String name, Object value) throws NoSuchFieldException {
Class<?> t = delegate.getDeclaredField(name).getType();
return value == null || t.isInstance(value) || t.isPrimitive() && isBoxCompatible(t, value.getClass());
} Try / catch
try { startProcess(key, vars); }
catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("Incompatible type set on field declaration")) {
log.error("Field injection type mismatch: {}", e.getMessage());
} else throw e;
} Prevention
- Match stringValue/expression elements to the declared field type
- Prefer String fields in delegates; convert types explicitly inside the delegate
- Document expected field types on each JavaDelegate
When it happens
Trigger: A <flowable:field> supplies a stringValue/expression whose runtime type (e.g. String) does not match the delegate field type (e.g. int, List, custom type), so the compatibility check fails before ReflectUtil.setField.
Common situations: Injecting a string into an Integer/List field without a matching type in the declaration; using expression results of unexpected type; switching a field's type in the delegate without updating process XML; confusion between stringValue, expression and object param types.
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
- Incompatible type set on field declaration '%s' for class %s
- Incompatible type set on field declaration '${name}' for cla
- Could not set field ${field}
- Field definition uses non-existing field '<fieldName>' on cl
- Illegal access when calling '%s' on class %s
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/83037c58c4ad8afb.
Report an issue: GitHub.