flowable/flowable-engine · error · TreeBuilderException

e.getMessage()

Error message

e.getMessage()

What it means

TreeBuilderImpl.build() parses an expression and, on ScanException or ParseException, rethrows it as a TreeBuilderException carrying the expression, error position, encountered text, expected tokens, and e.getMessage() as the detail message. It is the parse-failure path of the EL compiler — the expression string is syntactically invalid.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/tree/impl/Builder.java:108

		}
	}
	
	/**
	 * @return <code>true</code> iff the specified feature is supported.
	 */
	public boolean isEnabled(Feature feature) {
		return features.contains(feature);
	}
	
	/**
	 * Parse expression.
	 */
    @Override
	public Tree build(String expression) throws TreeBuilderException {
		try {
			return createParser(expression).tree();
		} catch (ScanException e) {
			throw new TreeBuilderException(expression, e.position, e.encountered, e.expected, e.getMessage());
		} catch (ParseException e) {
			throw new TreeBuilderException(expression, e.position, e.encountered, e.expected, e.getMessage());
		}
	}

	protected Parser createParser(String expression) {
		return new Parser(this, expression);
	}	
	
	@Override
	public boolean equals(Object obj) {
		if (obj == null || obj.getClass() != getClass()) {
			return false;
		}
		return features.equals(((Builder)obj).features);
	}
	
	@Override

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Fix the expression syntax at the reported position (the exception exposes position, encountered, and expected).
  2. Escape or remove characters not allowed by the EL grammar (quotes, '${' without matching '}').
  3. Validate expressions at deploy/build time using a TreeBuilder parse pass instead of at runtime.
  4. Catch TreeBuilderException and log expression + position to locate the offending definition quickly.

Example fix

// before
String expr = "${user.name " ; // unbalanced -> TreeBuilderException
// after
String expr = "${user.name}"; // or pre-validate:
try { treeBuilder.build(expr); } catch (TreeBuilderException e) {
    throw new IllegalArgumentException("Bad EL at " + e.getPosition() + ": " + expr);
}
Defensive patterns

Strategy: validation

Validate before calling

// pre-validate an expression before using it at runtime
try {
    new TreeBuilderImpl(new Builder()).build(expression);
} catch (TreeBuilderException e) {
    throw new IllegalArgumentException("Invalid EL at pos " + e.getPosition()
        + ", encountered '" + e.getEncountered() + "', expected " + e.getExpected());
}

Try / catch

try {
    Tree tree = treeBuilder.build(expression);
} catch (TreeBuilderException e) {
    log.error("EL parse error in '{}' at pos {}: encountered '{}' expected {}",
        e.getExpression(), e.getPosition(), e.getEncountered(), e.getExpected());
    throw new IllegalArgumentException("Malformed expression", e);
}

Prevention

When it happens

Trigger: build(expression) is invoked with a syntactically invalid EL string, e.g. unbalanced '${', bad escape sequences, or illegal token sequences, and the underlying parser throws ScanException/ParseException.

Common situations: Process definitions or templates containing broken expressions (missing '}', stray quotes); dynamically composed expressions where variable interpolation produced invalid EL; expressions containing characters the scanner does not accept (locale text, newlines).

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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