flowable/flowable-engine · error · ActivitiException
Illegal access when calling '%s' on class %s
Error message
Illegal access when calling '%s' on class %s
What it means
Thrown when applying a BPMN field injection declaration to a service task delegate via a setter method: the underlying setter's Method.invoke() raised IllegalAccessException, meaning the setter is not accessible (e.g. non-public) from the engine's reflection call. The engine wraps it in an ActivitiException naming the field and target class.
Source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/ClassDelegateUtil.java:58
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
- Make the setter method public on the delegate class
- Verify the flowable:field name attribute exactly matches an existing public setter (setXxx)
- Alternatively switch to direct field injection: make the target field public or use field name matching a public field
- Check the target class is the actual delegate class (not a subclass without the setter)
Example fix
// before
public class MyDelegate implements JavaDelegate {
private String value;
void setValue(String value) { this.value = value; }
}
// after
public class MyDelegate implements JavaDelegate {
private String value;
public void setValue(String value) { this.value = value; }
} Defensive patterns
Strategy: validation
Validate before calling
if (java.lang.reflect.Modifier.isPublic(delegate.getClass().getMethod("setValue", String.class).getModifiers())) { /* safe to inject */ } Prevention
- Always declare injected-field setters public
- Keep field names in BPMN XML in sync with delegate fields (IDE checks or unit test that applies declarations)
- Write a test that instantiates each delegate and applies its field declarations
When it happens
Trigger: A delegate class has a setter for an injected field declared in the BPMN XML (flowable:field) that is private/protected/package-private or otherwise not callable via reflection, and ClassDelegateUtil.applyFieldDeclaration invokes it.
Common situations: Hand-written delegates with non-public setters; copying delegate code between packages with different visibility; refactoring a public field into a private setter without making the setter public; proxies or restricted classloaders blocking access.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Exception while invoking '%s' on class %s
- Field definition uses non-existent field '${name}' of class
- Incompatible type set on field declaration '${name}' for cla
- Could not set field ${field}
- Illegal access when calling '<fieldName>' on class <classNam
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/a79dd62e2e1fdd4f.
Report an issue: GitHub.