apache/druid · error · ExpressionValidationException
first argument must be constant STRING expression containing
Error message
first argument must be constant STRING expression containing a valid complex type name but got '%s' instead
What it means
The complex_decode_base64 expression macro (BuiltInExprMacros.java) requires its first argument to be a constant STRING literal naming a complex type (e.g. 'complexTypeSerializers' payloads like 'druid.metrics.snapshot'). This validationFailed is thrown when the first argument is not a literal expression at all — e.g. a column reference, arithmetic, or another function call.
Source
Thrown at processing/src/main/java/org/apache/druid/math/expr/BuiltInExprMacros.java:67
@Override
public Expr apply(List<Expr> args)
{
return new ComplexDecodeBase64Expression(args);
}
final class ComplexDecodeBase64Expression extends ExprMacroTable.BaseScalarMacroFunctionExpr
{
private final ExpressionType complexType;
private final TypeStrategy<?> typeStrategy;
public ComplexDecodeBase64Expression(List<Expr> args)
{
super(ComplexDecodeBase64ExprMacro.this, args);
validationHelperCheckArgumentCount(args, 2);
final Expr arg0 = args.get(0);
if (!arg0.isLiteral()) {
throw validationFailed(
"first argument must be constant STRING expression containing a valid complex type name but got '%s' instead",
arg0.stringify()
);
}
if (arg0.isNullLiteral()) {
throw validationFailed("first argument must be constant STRING expression containing a valid complex type name but got NULL instead");
}
final Object literal = arg0.getLiteralValue();
if (!(literal instanceof String)) {
throw validationFailed(
"first argument must be constant STRING expression containing a valid complex type name but got '%s' instead",
arg0.getLiteralValue()
);
}
this.complexType = ExpressionTypeFactory.getInstance().ofComplex((String) literal);
try {
this.typeStrategy = complexType.getStrategy();View on GitHub (pinned to 9b90983fd2)
Solutions
- Replace the first argument with a constant string literal, e.g. complex_decode_base64('druid.metrics.snapshot', data_col).
- If the type name is dynamic, resolve it in the application layer before building the query.
- Check stringify() output in the error message to see what expression was actually passed.
- Use EXPLAIN to confirm the expression planner sees a literal.
Example fix
// before
SELECT complex_decode_base64(type_col, base64_col) FROM t
// after
SELECT complex_decode_base64('druid.metrics.snapshot', base64_col) FROM t Defensive patterns
Strategy: validation
When it happens
Trigger: Calling complex_decode_base64(expr, col) where the first argument is a non-literal expression such as a column reference, CONCAT('x','y'), or any computed expression instead of a quoted string literal.
Common situations: Writing SQL like complex_decode_base64(type_column, data_column) instead of hardcoding the type name; templated SQL where the type name is injected as a dynamic expression.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- first argument must be constant STRING expression containing
- needs a number as its first argument but got %s instead
- needs a LONG as its second argument but got null
- needs a LONG as its second argument but got %s instead
- given precision[%d] must be in the range of [0,3]
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/ef115c1077a509ff.
Report an issue: GitHub.