flowable/flowable-engine · error · FlowableIllegalArgumentException

Variable type must be byte[] or string

Error message

Variable type must be byte[] or string

What it means

VariableBase64ExpressionFunction.base64 (EL function vars:base64) converts a variable to a Base64 string, but only Byte[]/byte[] and String values are supported. Any other variable type (Integer, Serializable bean, List, etc.) cannot be encoded, so a FlowableIllegalArgumentException is thrown.

Solutions

  1. Convert the variable to a String or byte[] before encoding, e.g. ${vars:base64(myVar.toString())} or serialize the object first in a delegate.
  2. Pass a String variable directly if the content is textual.
  3. Update the variable mapping (script/delegate) to produce byte[] or String for the target variable.
  4. If encoding arbitrary objects is needed, implement custom serialization in a service task instead of the EL function.

Example fix

// before
${vars:base64(orderId)}   // orderId is Integer -> throws

// after
${vars:base64(orderId.toString())}
Defensive patterns

Strategy: type-guard

Validate before calling

Object v = execution.getVariable("myVar");
if (v != null && !(v instanceof byte[]) && !(v instanceof Byte[]) && !(v instanceof String)) {
    throw new IllegalArgumentException("vars:base64 requires byte[]/Byte[]/String, got " + v.getClass());
}

Type guard

boolean base64Encodable(Object v) {
    return v == null || v instanceof String || v instanceof byte[] || v instanceof Byte[];
}

Try / catch

try {
    Object encoded = expressionManager.evaluateExpression(base64Expr, execution);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("byte[] or string")) {
        // fall back to serializing the object to String first
    }
    throw e;
}

Prevention

When it happens

Trigger: Evaluating ${vars:base64(myVar)} where myVar is of a type other than byte[], Byte[], or String — e.g. an Integer, a POJO, a JSON node, or a Date.

Common situations: Misremembering which types the base64 function accepts; passing a numeric or object variable expecting implicit conversion to bytes/string; version differences where a variable's type changed (e.g. stored as String previously, now a POJO).

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

Appendix: source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/el/function/VariableBase64ExpressionFunction.java:39

 * @author Joram Barrez
 */
public class VariableBase64ExpressionFunction extends AbstractFlowableVariableExpressionFunction {
    
    public VariableBase64ExpressionFunction() {
        super("base64");
    }
    
    public static Object base64(VariableContainer variableContainer, String variableName) {
        Object value = getVariableValue(variableContainer, variableName);

        if (value == null) {
            return null;
        } else if (value instanceof Byte[] || value instanceof byte[]) {
            return java.util.Base64.getEncoder().encodeToString( (byte[]) value);
        } else if (value instanceof String) {
            return java.util.Base64.getEncoder().encodeToString(((String) value).getBytes());
        } else {
            throw new FlowableIllegalArgumentException("Variable type must be byte[] or string");
        }
    }

}

View on GitHub (pinned to d6d39ce1c6)