flowable/flowable-engine · error · FlowableIllegalArgumentException

Unsupported variable query operation: ${variable.getVariable

Error message

Unsupported variable query operation: ${variable.getVariableOperation()}

What it means

Catch-all FlowableIllegalArgumentException in the operation switch: the requested QueryVariableOperation has no branch in the historic case instance variable query builder, so it is unsupported for this endpoint.

Source

Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/history/caze/HistoricCaseInstanceBaseResource.java:392

            case LESS_THAN:
                caseInstanceQuery.variableValueLessThan(variable.getName(), actualValue);
                break;

            case LESS_THAN_OR_EQUALS:
                caseInstanceQuery.variableValueLessThanOrEqual(variable.getName(), actualValue);
                break;

            case EXISTS:
                caseInstanceQuery.variableExists(variable.getName());
                break;

            case NOT_EXISTS:
                caseInstanceQuery.variableNotExists(variable.getName());
                break;

            default:
                throw new FlowableIllegalArgumentException("Unsupported variable query operation: " + variable.getVariableOperation());
            }
        }
    }
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Use a supported operation: equals, notEquals, equalsIgnoreCase, notEqualsIgnoreCase, like, likeIgnoreCase, greaterThan, greaterThanOrEquals, lessThan, lessThanOrEquals, exists, notExists
  2. Align client Flowable REST version with the server version
  3. Log and inspect the exact operation string being sent
  4. Add server-side handling if you own a fork and need the extra operation

Example fix

// before
{"name":"x","operation":"between","value":1}
// after
{"name":"x","operation":"greaterThanOrEquals","value":1} // plus a lessThanOrEquals variable
Defensive patterns

Strategy: validation

Validate before calling

Set<String> SUPPORTED = Set.of("equals","notEquals","equalsIgnoreCase","notEqualsIgnoreCase","like","likeIgnoreCase","greaterThan","greaterThanOrEquals","lessThan","lessThanOrEquals","exists","notExists");
if (!SUPPORTED.contains(op)) throw new IllegalArgumentException("Unsupported operation: " + op);

Type guard

boolean isSupportedOperation(String op) {
  return java.util.EnumSet.allOf(QueryVariableOperation.class).stream()
    .map(Enum::name).map(n -> n.replace('_',' ').toLowerCase()).anyMatch(op::equals);
}

Try / catch

try { ... } catch (FlowableIllegalArgumentException e) {
  log.error("Unsupported variable operation: {}", e.getMessage());
  return badRequest(e.getMessage());
}

Prevention

When it happens

Trigger: POST query with an operation value that deserializes to an enum the switch does not handle (newer/older enum member, or a custom operation name).

Common situations: Client and server version mismatch — client sends an operation added in a newer Flowable version; typos that still deserialize; copy-pasted operation from a task/process query supporting more operations.

Related errors


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