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
- Convert the variable to a String or byte[] before encoding, e.g. ${vars:base64(myVar.toString())} or serialize the object first in a delegate.
- Pass a String variable directly if the content is textual.
- Update the variable mapping (script/delegate) to produce byte[] or String for the target variable.
- 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
- Map variables to String or byte[] before applying vars:base64.
- Document the accepted types where the expression is used in process definitions.
- Add process-definition validation for expressions applying vars:base64 to non-string variables.
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
- Cannot coerce property to array index:
- Cannot coerce property to array index:
- error.compare.types
- error.function.access
- error.negate
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)