flowable/flowable-engine · error · IllegalStateException

The [ ] must resolve to an Number or a String that can be…

Error message

The [<attribute>] must resolve to an Number or a String that can be parsed as a Double. Resolved to [<class>] for [<value>]

What it means

resolveExpressionAsDouble resolves an attribute expression expecting a Double, Double-parseable String, or null; anything else throws IllegalStateException. It backs the retry backoff multiplier, so a wrongly typed multiplier expression triggers this during endpoint creation.

Solutions

  1. Set multiplier to a numeric value or numeric String with a decimal point, e.g. 2.0 or "2.0".
  2. Fix the referenced property so it is a Double, not a collection/boolean.
  3. Check the expression/placeholder key for typos resolving to an unrelated bean.
  4. Use a dot as decimal separator; avoid locale-formatted strings.

Example fix

// before
flowable:
  kafka:
    retry:
      multiplier: [2.0, 3.0]   # resolves to a List

// after
flowable:
  kafka:
    retry:
      multiplier: 2.0
Defensive patterns

Strategy: type-guard

Validate before calling

Object v = resolveExpression(value);
if (v != null && !(v instanceof Number) && !(v instanceof String)) throw new IllegalArgumentException(attribute + " must be double-like");

Type guard

boolean isDoubleLike(Object v) { return v == null || v instanceof Number || (v instanceof String s && s.matches("-?\\d+(\\.\\d+)?")); }

Try / catch

try { ... } catch (IllegalStateException e) { if (e.getMessage().contains("parsed as a Double")) { log.error("Backoff multiplier not a Double: {}", e.getMessage()); } else throw e; }

Prevention

When it happens

Trigger: The multiplier attribute of the retry backoff configuration resolves to a type that is neither Number, String, nor null (e.g. Boolean, List) when resolveRetryConfiguration builds the retry template.

Common situations: Multiplier bound to a boolean flag by mistake; placeholder points at a list of multipliers instead of a single value; locale-formatted decimal string like "1,5" fails parse (NumberFormatException) vs wrong class here is object type mismatch.

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/faad1908fe8c3131. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java:492

        } else if (resolved instanceof Number) {
            result = ((Number) resolved).longValue();
        } else if (resolved != null) {
            throw new IllegalStateException(
                    "The [" + attribute + "] must resolve to an Number or a String that can be parsed as a Long. "
                            + "Resolved to [" + resolved.getClass() + "] for [" + value + "]");
        }
        return result;
    }

    protected Double resolveExpressionAsDouble(String value, String attribute) {
        Object resolved = resolveExpression(value);
        Double result = null;
        if (resolved instanceof String) {
            result = Double.parseDouble((String) resolved);
        } else if (resolved instanceof Number) {
            result = ((Number) resolved).doubleValue();
        } else if (resolved != null) {
            throw new IllegalStateException(
                    "The [" + attribute + "] must resolve to an Number or a String that can be parsed as a Double. "
                            + "Resolved to [" + resolved.getClass() + "] for [" + value + "]");
        }
        return result;
    }

    protected Boolean resolveExpressionAsBoolean(String value, String attribute) {
        return resolveExpressionAsBoolean(value, attribute, null);
    }

    protected Boolean resolveExpressionAsBoolean(String value, String attribute, Boolean defaultValue) {
        Object resolved = resolveExpression(value);
        Boolean result = defaultValue;
        if (resolved instanceof String) {
            result = Boolean.parseBoolean((String) resolved);
        } else if (resolved instanceof Boolean) {
            result = (Boolean) resolved;
        } else if (resolved != null) {

View on GitHub (pinned to d6d39ce1c6)