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

  1. Replace the first argument with a constant string literal, e.g. complex_decode_base64('druid.metrics.snapshot', data_col).
  2. If the type name is dynamic, resolve it in the application layer before building the query.
  3. Check stringify() output in the error message to see what expression was actually passed.
  4. 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


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/ef115c1077a509ff. Report an issue: GitHub.