flowable/flowable-engine · error · ELException

Error reading '' on type ''

Error message

Error reading '' on type ''

What it means

BeanELResolver.getValue wraps exceptions thrown by a bean's getter invoked during EL evaluation in an ELException with the message "Error reading '<property>' on type '<class>'". The underlying InvocationTargetException cause (the real error inside the getter) is attached as the cause.

Source

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

		if (base == null || property == null) {
			return null;
		}

		BeanProperty beanProperty = property(base, property);
		if (beanProperty == null) {
			return null;
		}
		Method m = beanProperty.read(base);
		if (m == null) {
			return null;
		}
		context.setPropertyResolved(base, property);
		try {
			return invoke(m, base, (Object[]) null);
		} catch (InvocationTargetException e) {
			Throwable cause = e.getCause();
			Util.handleThrowable(cause);
            throw new ELException("Error reading '" + property + "' on type '" + base.getClass().getName() + "'", cause);
		} catch (Exception e) {
			throw new ELException(e);
		}
	}

	@Override
	public void setValue(ELContext context, Object base, Object property, Object value) {
		Objects.requireNonNull(context, "context is null");
		if (base == null || property == null) {
			return;
		}

		if (readOnly) {
			throw new PropertyNotWritableException("resolver is read-only");
		}
		BeanProperty beanProperty = property(base, property);

		if (beanProperty == null) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Inspect the cause chain of the ELException — the fix belongs in the getter that threw, not the EL layer.
  2. Make the getter null-safe / fail-fast for uninitialized state.
  3. Precompute the value before evaluation and pass it as a plain variable instead of relying on a throwing getter.

Example fix

// before
public String getName() { return owner.getName(); } // NPEs when owner is null
// after
public String getName() { return owner != null ? owner.getName() : null; }
Defensive patterns

Strategy: try-catch

Validate before calling

// before evaluation: invoke the getters yourself
for (String p : props) { try { new PropertyDescriptor(p, bean.getClass()).getReadMethod().invoke(bean); } catch (Exception e) { /* fix getter */ } }

Try / catch

try { v = resolver.getValue(ctx, bean, prop); } catch (ELException e) { log.error("getter failed for " + prop, e.getCause()); }

Prevention

When it happens

Trigger: Evaluating ${bean.someProperty} where calling the corresponding getXxx() method throws any exception (NPE, IllegalStateException, remote call failure, etc.).

Common situations: Getters with side effects (lazy DB/service lookups) failing at expression evaluation time in process expressions, forms, or templates; getter NPEs on not-yet-initialized fields.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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