flowable/flowable-engine · error · ActivitiIllegalArgumentException
Field definition uses unexisting field
Error message
Field definition uses unexisting field '%s' on class %s
What it means
When no setter matches the field declaration name, ClassDelegate falls back to direct field injection. If neither a setter nor a field with that name exists on the delegate class and throwExceptionOnMissingField is true (default), an ActivitiIllegalArgumentException is thrown naming the missing field and class. This catches typos in activiti:field declarations at first use.
Solutions
- Fix the field name in the BPMN XML (or delegateExpression config) to match an existing setter/field on the delegate class.
- Add the missing setter/field to the delegate class.
- If the field is intentionally optional, construct ClassDelegate with throwExceptionOnMissingField=false.
Example fix
// before (BPMN) <activiti:field name="receipent"><activiti:string>x</activiti:string></activiti:field> // after <activiti:field name="recipient"><activiti:string>x</activiti:string></activiti:field> // matching: public void setRecipient(String recipient)
Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = delegateClass;
boolean ok = Arrays.stream(c.getMethods()).anyMatch(m -> m.getName().equals("set" + capitalize(fieldName)))
|| Arrays.stream(c.getDeclaredFields()).anyMatch(f -> f.getName().equals(fieldName));
if (!ok) throw new IllegalStateException("Field '" + fieldName + "' missing on " + c.getName()); Type guard
boolean fieldExists(Class<?> c, String name) {
try { c.getDeclaredField(name); return true; }
catch (NoSuchFieldException e) {
return Arrays.stream(c.getMethods()).anyMatch(m -> m.getName().equalsIgnoreCase("set" + name));
}
} Try / catch
try {
applyFieldDeclaration(declaration, target, true);
} catch (ActivitiIllegalArgumentException e) {
if (e.getMessage().contains("unexisting field")) {
log.error("activiti:field name '{}' does not exist on {}", declaration.getName(), target.getClass(), e);
} else throw e;
} Prevention
- Cross-check every activiti:field name against the delegate's setters/fields before deploying
- Grep process XML field names in CI against delegate sources
- Rename field and setter together and update all referencing process definitions
When it happens
Trigger: BPMN XML declares <activiti:field name="foo"> but the delegate class has neither setFoo(...) nor a member foo; ClassDelegate was constructed with throwExceptionOnMissingField=true.
Common situations: Typo in the field name in process XML; delegate refactored/renamed the field or setter while old process definitions still deployed; copying field declarations between delegates with different property names.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Incompatible type set on field declaration
- Error while invoking
- Error while invoking
- Error while invoking
- Exception while invoking
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/f03ac7a768ab85fb.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/ClassDelegate.java:281
public static void applyFieldDeclaration(FieldDeclaration declaration, Object target, boolean throwExceptionOnMissingField) {
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) {
if (throwExceptionOnMissingField) {
throw new ActivitiIllegalArgumentException("Field definition uses unexisting field '" + declaration.getName() + "' on class " + target.getClass().getName());
} else {
return;
}
}
// 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());
}
}
public static boolean fieldTypeCompatible(FieldDeclaration declaration, Field field) {View on GitHub (pinned to d6d39ce1c6)