flowable/flowable-engine · error · ActivitiIllegalArgumentException

Only string values can be used with 'like' condition

Error message

Only string values can be used with 'like' condition

What it means

ActivitiIllegalArgumentException thrown by addVariable when a LIKE or LIKE_IGNORE_CASE condition receives a non-String value. SQL LIKE-style pattern matching operates on strings, so the engine requires the value to be a String and rejects anything else (including null, rejected earlier) at query-build time.

Solutions

  1. Convert numeric/other values to String before using LIKE: variableValueLike(name, String.valueOf(num)).
  2. Use variableValueEquals for exact non-string matches instead of pattern matching.
  3. Validate that LIKE filter inputs are Strings (and non-null) before building the query.

Example fix

// before
query.taskVariableLike("caseNumber", caseNumber); // Integer
// after
query.taskVariableLike("caseNumber", "%" + String.valueOf(caseNumber) + "%");
Defensive patterns

Strategy: type-guard

Validate before calling

if (pattern instanceof String) {
    query.taskVariableLike(name, (String) pattern);
} else if (pattern != null) {
    query.taskVariableValueEquals(name, pattern);
}

Type guard

boolean isString(Object o) { return o instanceof String; }

Try / catch

try {
    query.taskVariableLike(name, pattern);
} catch (ActivitiIllegalArgumentException e) {
    log.warn("Like filter requires a String: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling variableValueLike(name, 123), variableValueLikeIgnoreCase(name, someObject), or a generic search builder feeding untyped filter input into LIKE methods.

Common situations: Search forms with untyped inputs (numbers for IDs) mapped to 'contains' filters; a numeric variable queried with a pattern filter that was never converted to 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/4512c87de646d718. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/AbstractVariableQueryImpl.java:196

                    throw new ActivitiIllegalArgumentException("Booleans and null cannot be used in 'greater than' condition");
                case LESS_THAN:
                    throw new ActivitiIllegalArgumentException("Booleans and null cannot be used in 'less than' condition");
                case GREATER_THAN_OR_EQUAL:
                    throw new ActivitiIllegalArgumentException("Booleans and null cannot be used in 'greater than or equal' condition");
                case LESS_THAN_OR_EQUAL:
                    throw new ActivitiIllegalArgumentException("Booleans and null cannot be used in 'less than or equal' condition");
            }

            if (operator == QueryOperator.EQUALS_IGNORE_CASE && !(value instanceof String)) {
                throw new ActivitiIllegalArgumentException("Only string values can be used with 'equals ignore case' condition");
            }

            if (operator == QueryOperator.NOT_EQUALS_IGNORE_CASE && !(value instanceof String)) {
                throw new ActivitiIllegalArgumentException("Only string values can be used with 'not equals ignore case' condition");
            }

            if ((operator == QueryOperator.LIKE || operator == QueryOperator.LIKE_IGNORE_CASE) && !(value instanceof String)) {
                throw new ActivitiIllegalArgumentException("Only string values can be used with 'like' condition");
            }
        }
        queryVariableValues.add(new QueryVariableValue(name, value, operator, localScope));
    }

    private boolean isBoolean(Object value) {
        if (value == null) {
            return false;
        }
        return Boolean.class.isAssignableFrom(value.getClass()) || boolean.class.isAssignableFrom(value.getClass());
    }

    protected void ensureVariablesInitialized() {
        if (!queryVariableValues.isEmpty()) {
            VariableTypes variableTypes = Context
                    .getProcessEngineConfiguration()
                    .getVariableTypes();
            for (QueryVariableValue queryVariableValue : queryVariableValues) {

View on GitHub (pinned to d6d39ce1c6)