flowable/flowable-engine · error · PropertyNotFoundException

Property ' ' not found on type

Error message

Property '${propertyName}' not found on type '${base.getClass().getName()}'

What it means

RecordELResolver.getValue resolves record component accessors via reflection: it looks up a public no-arg method named exactly like the property on the record class. If getMethod finds no such accessor it wraps the NoSuchMethodException in a PropertyNotFoundException.

Solutions

  1. Fix the property name in the expression to match the record component exactly (case-sensitive)
  2. Add or rename the record component/accessor to match the expression
  3. Check the record class version on the classpath matches what the expression expects
  4. Catch PropertyNotFoundException during EL evaluation and log the expression and type

Example fix

// before
public record Order(String OrderRef) {}
${order.orderRef} // not found: component is OrderRef
// after
public record Order(String orderRef) {}
${order.orderRef}
Defensive patterns

Strategy: validation

Validate before calling

boolean hasProperty(Class<?> t, String name){ try { t.getMethod(name); return true; } catch (NoSuchMethodException e){ return false; } }

Type guard

boolean isRecordAccessor(Class<?> t, String n){ return java.lang.reflect.RecordComponent.class.isAssignableFrom(Object.class) && hasProperty(t, n); }

Try / catch

try { return expr.getValue(ctx); } catch (PropertyNotFoundException e) { log.error("Unknown EL property: {}", e.getMessage()); throw e; }

Prevention

When it happens

Trigger: Evaluating ${record.property} where the record has no component (or accessor method) with that exact name; typos in property names; using a method name that exists but with parameters or is inherited/non-accessor.

Common situations: Renaming a record component without updating EL expressions in process/BPMN XML; expressions written for POJO getters (e.g. getName) applied to records that expose name(); case mismatch (Name vs name).


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/6a549dc54d6cec97. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/javax/el/RecordELResolver.java:70

     * @throws PropertyNotFoundException if the {@code base} is an instance of {@link Record} and the specified property
     * does not exist.
     * @throws ELException if an exception was throws while performing the property resolution. The thrown
     * exception must be included as the cause of this exception, if available.
     */
    @Override
    public Object getValue(ELContext context, Object base, Object property) {
        Objects.requireNonNull(context);

        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>

View on GitHub (pinned to d6d39ce1c6)