flowable/flowable-engine · error · FlowableIllegalArgumentException

Variables of type ByteArray cannot be used to query

Error message

Variables of type ByteArray cannot be used to query

What it means

QueryVariableValue.initialize(VariableValueProvider) resolves the variable type of the value used in a variable-value query predicate. If the resolved type is ByteArrayType, the value would be stored in a separate byte-array table that cannot be matched in a SQL query predicate, so Flowable throws FlowableIllegalArgumentException("Variables of type ByteArray cannot be used to query").

Source

Thrown at modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/QueryVariableValue.java:60

    private String scopeType;

    public QueryVariableValue(String name, Object value, QueryOperator operator, boolean local) {
        this.name = name;
        this.value = value;
        this.operator = operator;
        this.local = local;
    }

    public QueryVariableValue(String name, Object value, QueryOperator operator, boolean local, String scopeType) {
        this(name, value, operator, local);
        this.scopeType = scopeType;
    }

    public void initialize(VariableValueProvider valueProvider) {
        if (valueField == null) {
            valueType = valueProvider.findVariableType(value);
            if (valueType instanceof ByteArrayType) {
                throw new FlowableIllegalArgumentException("Variables of type ByteArray cannot be used to query");
            } else if (valueType instanceof JPAEntityVariableType && operator != QueryOperator.EQUALS) {
                throw new FlowableIllegalArgumentException("JPA entity variables can only be used in 'variableValueEquals'");
            } else if (valueType instanceof JPAEntityListVariableType) {
                throw new FlowableIllegalArgumentException("Variables containing a list of JPA entities cannot be used to query");
            } else {
                // Type implementation determines which fields are set on the entity
                valueField = valueProvider.createValueFields(name, valueType, value);
            }
        }
    }

    public void initialize(VariableServiceConfiguration variableServiceConfiguration) {
        initialize(new VariableServiceConfigurationVariableValueProvider(variableServiceConfiguration));
    }

    public String getName() {
        return name;
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Query on a primitive/serializable value instead (String, Long, Double, Boolean, Date).
  2. Store a searchable companion variable (e.g. a hash or name) alongside the byte-array variable and query that.
  3. If you must find it, fetch candidate variables and filter byte-array content in application code.

Example fix

// before
taskQuery.variableValueEquals("attachment", fileBytes); // throws

// after
taskQuery.variableValueEquals("attachmentName", file.getName());
Defensive patterns

Strategy: type-guard

Validate before calling

boolean queryable = !(value instanceof byte[])
    && !(value instanceof InputStream)
    && !(value instanceof Serializable && !(value instanceof String || value instanceof Number || value instanceof Boolean || value instanceof java.util.Date));

Type guard

static boolean isQueryableVariableValue(Object v) {
    return v == null || v instanceof String || v instanceof Boolean
        || v instanceof Integer || v instanceof Long || v instanceof Double
        || v instanceof java.util.Date;
}

Try / catch

try {
    taskQuery.variableValueEquals(name, value);
} catch (FlowableIllegalArgumentException e) {
    // fall back to querying a shadow scalar variable
    taskQuery.variableValueEquals(name + "_key", computeKey(value));
}

Prevention

When it happens

Trigger: Calling taskService.createTaskQuery().variableValueEquals("var", someByteArrayOrSerializableObject) (or any variableValue* operator) where the value resolves to ByteArrayType, e.g. a byte[], InputStream, or Serializable stored as bytes.

Common situations: Attempting to search variables that hold file contents or serialized objects; assuming all variable types are queryable; passing an object that Flowable persists as bytes because it is not one of the primitive queryable types.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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