flowable/flowable-engine · error · ELException
Error reading ' ' on type
Error message
Error reading '${propertyName}' on type '${base.getClass().getName()}' What it means
RecordELResolver.getValue found the record's accessor method via reflection but Method.invoke failed (IllegalAccessException, InvocationTargetException from an accessor that threw, etc.). It rethrows as ELException with the property and type named for diagnosis.
Solutions
- Inspect the cause (ReflectiveOperationException) for the real failure and fix the accessor logic
- Ensure the record class/package is exported/opened to the EL engine module under JPMS
- Null-check inputs used by the accessor so it cannot throw during evaluation
- Catch ELException, unwrap getCause(), and surface the root cause
Example fix
// before
public record Cfg(String value) { public String value() { return value.trim(); } } // NPE if value null
// after
public record Cfg(String value) { public String value() { return value == null ? "" : value.trim(); } } Defensive patterns
Strategy: try-catch
Validate before calling
if (value == null && accessorPerformsOperations) throw new IllegalStateException("accessor would NPE"); Try / catch
try { return expr.getValue(ctx); } catch (ELException e) { Throwable root = e.getCause(); log.error("Accessor failed on {} : {}", type, root, root); throw root instanceof RuntimeException r ? r : new IllegalStateException(root); } Prevention
- Make record accessors null-safe
- Ensure JPMS exports/opens the record package to the EL module
- Log and inspect ELException.getCause()
- Avoid throwing logic inside accessors
When it happens
Trigger: The record accessor itself throws an exception during evaluation; the accessor is public on the method but its declaring class is not accessible to the caller (illegal access); the resolved method's body throws (e.g. validation in a compact constructor-dependent accessor).
Common situations: Accessor lazily computes and fails (NPE inside accessor); records from another module/package not opened to the EL module (JPMS strong encapsulation); a nested exception in a record built from external data.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/2898cab8ca41661d.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/javax/el/RecordELResolver.java:79
if (base instanceof Record && property != null) {
context.setPropertyResolved(base, property);
String propertyName = property.toString();
Method method;
try {
method = base.getClass().getMethod(propertyName);
} catch (NoSuchMethodException nsme) {
throw new PropertyNotFoundException("Property '" + propertyName + "' not found on type '" + base.getClass().getName() + "'", nsme);
}
if (Modifier.isPublic(method.getModifiers())) {
method.trySetAccessible();
}
try {
return method.invoke(base);
} catch (ReflectiveOperationException e) {
throw new ELException("Error reading '" + propertyName + "' on type '" + base.getClass().getName() + "'", e);
}
}
return null;
}
/**
* If the base object is an instance of {@link Record}, always returns {@code null} since {@link Record}s are always
* read-only.
* <p>
* If the base object is an instance of {@link Record}, the {@code propertyResolved} property of the provided
* {@link ELContext} must be set to {@code true} by this resolver before returning. If this property is not {@code
* true} after this method is called, the caller should ignore the return value.
*
* @param context The context of this evaluation.
* @param base The {@link Record} to analyze.
* @param property The name of the property to analyze. Will be coerced to a String.
* @return Always {@code null}
* @throws NullPointerException if the provided {@link ELContext} is {@code null}.View on GitHub (pinned to d6d39ce1c6)