flowable/flowable-engine · error · ELException

error.coerce.type

error.coerce.type

Error message

error.coerce.type

What it means

This error is thrown by the Flowable-bundled Odysseus EL TypeConverterImpl when a value cannot be coerced to Boolean. The coercion path accepts null/empty (false), Boolean, String, and LambdaExpression (resolved and retried); any other object type reaches the final throw and triggers error.coerce.type. It is wrapped in jakarta/javax ELException.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/misc/TypeConverterImpl.java:49

 * Type Conversions as described in EL 2.1 specification (section 1.17).
 */
public class TypeConverterImpl implements TypeConverter {
	private static final long serialVersionUID = 1L;

	protected Boolean coerceToBoolean(Object value) {
		if (value == null || "".equals(value)) {
			return Boolean.FALSE;
		}
		if (value instanceof Boolean) {
			return (Boolean)value;
		}
		if (value instanceof String) {
			return Boolean.valueOf((String)value);
		}
        if (value instanceof LambdaExpression lambdaExpression) {
            return coerceToBoolean(resolveLambdaExpression(lambdaExpression));
        }
		throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), Boolean.class));
	}

	protected Character coerceToCharacter(Object value) {
		if (value == null || "".equals(value)) {
			return Character.valueOf((char)0);
		}
		if (value instanceof Character) {
			return (Character)value;
		}
		if (value instanceof Number) {
			return Character.valueOf((char)((Number)value).shortValue());
		}
		if (value instanceof String) {
			return Character.valueOf(((String)value).charAt(0));
		}
        if (value instanceof LambdaExpression lambdaExpression) {
            return coerceToCharacter(resolveLambdaExpression(lambdaExpression));
        }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Fix the EL expression or bean so it evaluates to a Boolean or String parsable by Boolean.valueOf (e.g. ${order.approved} instead of ${order.status}).
  2. Convert the value in your bean/delegate before returning (e.g. return "true"/"false" or Boolean).
  3. Catch ELException in your expression-evaluation call site and log the offending expression/value.
  4. If using a custom ELResolver, ensure it only resolves values of types the converter supports.

Example fix

// before
<conditionExpression>${order.status}</conditionExpression>
// after
<conditionExpression>${order.status == 'APPROVED'}</conditionExpression>
Defensive patterns

Strategy: type-guard

Validate before calling

boolean valid = value == null || value instanceof Boolean || value instanceof String || value instanceof Number;

Type guard

static boolean isBooleanCoercible(Object v) { return v == null || v instanceof Boolean || v instanceof String || v instanceof org.flowable.common.engine.impl.de.odysseus.el.tree.impl.ast.LambdaExpression; }

Try / catch

try { Object r = expression.getValue(context); } catch (jakarta.el.ELException e) { log.error("EL boolean coercion failed: {}", e.getMessage()); }

Prevention

When it happens

Trigger: An EL expression evaluates to a non-String, non-Boolean object (e.g. a Number, Date, or POJO) where a boolean result is required, such as in an ${...} condition used by a Flowable condition expression, delegate, or JSP-style EL evaluation.

Common situations: Condition expressions on sequence flows returning numeric IDs instead of booleans; beans returning wrapper objects; version upgrades (Java 17 pattern matching variant) where a resolver now yields a typed object instead of a String.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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