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
- Convert numeric/other values to String before using LIKE: variableValueLike(name, String.valueOf(num)).
- Use variableValueEquals for exact non-string matches instead of pattern matching.
- 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
- Convert numeric IDs to Strings before pattern matching
- Reserve LIKE methods for string patterns; use equals for exact typed matches
- Validate 'contains' filter inputs are strings at the form/API boundary
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
- Only string values can be used with 'equals ignore case'…
- Only string values can be used with 'not equals ignore…
- activity tenant id is null
- Booleans and null cannot be used in 'greater than' condition
- Booleans and null cannot be used in 'greater than or equal'…
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)