flowable/flowable-engine · error · ELException

Cannot parse EL property ${PROP_CACHE_SIZE}

Error message

Cannot parse EL property ${PROP_CACHE_SIZE}

What it means

createTreeStore() reads the PROP_CACHE_SIZE property to size the expression parse-tree cache. If the value is not a valid integer, NumberFormatException is wrapped in ELException 'Cannot parse EL property ${PROP_CACHE_SIZE}'. The property must parse via Integer.parseInt.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/ExpressionFactoryImpl.java:350

			if (getFeatureProperty(profile, properties, Feature.VARARGS, PROP_VAR_ARGS)) {
				features.add(Builder.Feature.VARARGS);
			}
			if (getFeatureProperty(profile, properties, Feature.NULL_PROPERTIES, PROP_NULL_PROPERTIES)) {
				features.add(Builder.Feature.NULL_PROPERTIES);
			}
			if (getFeatureProperty(profile, properties, Feature.IGNORE_RETURN_TYPE, PROP_IGNORE_RETURN_TYPE)) {
				features.add(Builder.Feature.IGNORE_RETURN_TYPE);
			}
			builder = createTreeBuilder(properties, features.toArray(new Builder.Feature[0]));
		}

		// create cache
		int cacheSize = defaultCacheSize;
		if (properties != null && properties.containsKey(PROP_CACHE_SIZE)) {
			try {
				cacheSize = Integer.parseInt(properties.getProperty(PROP_CACHE_SIZE));
			} catch (NumberFormatException e) {
				throw new ELException("Cannot parse EL property " + PROP_CACHE_SIZE, e);
			}
		}
		Cache cache = cacheSize > 0 ? new Cache(cacheSize) : null;

		return new TreeStore(builder, cache);
	}

	/**
	 * Create the factory's type converter. This implementation takes the
	 * <code>de.odysseus.el.misc.TypeConverter</code> property as the name of a class implementing
	 * the <code>de.odysseus.el.misc.TypeConverter</code> interface. If the property is not set, the
	 * default converter (<code>TypeConverter.DEFAULT</code>) is used.
	 */
	protected TypeConverter createTypeConverter(Properties properties) {
		Class<?> clazz = load(TypeConverter.class, properties);
		if (clazz == null) {
			return TypeConverter.DEFAULT;
		}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Set the cache size property to a plain integer literal, e.g. 1024
  2. Remove the property entirely to fall back to defaultCacheSize
  3. Check for unresolved ${...} placeholders left by property substitution in the config file

Example fix

// before
dep.odysseus.el.tree.impl.TreeStore.cacheSize = 512m

// after
de.odysseus.el.tree.impl.TreeStore.cacheSize = 512
Defensive patterns

Strategy: validation

Validate before calling

String raw = props.getProperty("de.odysseus.el.tree.impl.TreeStore.cacheSize");
if (raw != null && !raw.trim().matches("\\d+")) {
    throw new IllegalArgumentException("cacheSize must be a plain integer, got: " + raw);
}

Try / catch

try {
    ExpressionFactory factory = new ExpressionFactoryImpl(props);
} catch (ELException e) {
    if (e.getMessage().contains("Cannot parse EL property")) {
        log.error("Fix cacheSize property to an integer literal", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Constructing ExpressionFactoryImpl with a Properties map containing a non-numeric value for the cache-size key (e.g. "1024m", "1,024", or whitespace-polluted value); also happens when a custom properties file supplies the key with a bad value.

Common situations: Tuning the EL cache by editing a properties file by hand and using a suffix or thousands separator; environment-specific property substitution that left a placeholder unresolved.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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