apache/druid · error · RE

Unable to transform apply function:[%s]

Error message

Unable to transform apply function:[%s]

What it means

During unapply/lifting of lambda-apply expressions (rewriteUnappliedSubExpressions → liftApplyLambda), Parser only knows how to transform specific apply functions (e.g. CartesianFoldFunction). Reaching the default branch means an ApplyFunctionExpr uses an apply function the lift transformation does not support, so RE 'Unable to transform apply function:[%s]' is thrown.

Source

Thrown at processing/src/main/java/org/apache/druid/math/expr/Parser.java:612

            new ArrayList<>(expr.lambdaExpr.getIdentifiers().size() + unappliedLambdaBindings.size());
        final List<IdentifierExpr> existingFoldLambdaIdentifiers = expr.lambdaExpr.getIdentifierExprs();
        // accumulator argument is last argument, slice it off when constructing new arg list and lambda args
        for (int i = 0; i < expr.argsExpr.size() - 1; i++) {
          newFoldArgs.add(expr.argsExpr.get(i));
          newFoldLambdaIdentifiers.add(existingFoldLambdaIdentifiers.get(i));
        }
        newFoldArgs.addAll(unappliedLambdaBindings);
        newFoldLambdaIdentifiers.addAll(unappliedLambdaBindings);
        // add accumulator last
        newFoldLambdaIdentifiers.add(existingFoldLambdaIdentifiers.get(existingFoldLambdaIdentifiers.size() - 1));
        newFoldArgs.add(expr.argsExpr.get(expr.argsExpr.size() - 1));
        final LambdaExpr newFoldLambda = new LambdaExpr(newFoldLambdaIdentifiers, expr.lambdaExpr.getExpr());

        newFn = new ApplyFunction.CartesianFoldFunction();
        newExpr = new ApplyFunctionExpr(newFn, newFn.name(), newFoldLambda, newFoldArgs);
        break;
      default:
        throw new RE("Unable to transform apply function:[%s]", expr.function.name());
    }

    return newExpr;
  }

  /**
   * Validate that an expression uses input bindings in a type consistent manner.
   */
  public static void validateExpr(Expr expression, Expr.BindingAnalysis bindingAnalysis)
  {
    final Set<String> conflicted =
        Sets.intersection(bindingAnalysis.getScalarBindings(), bindingAnalysis.getArrayBindings());
    if (!conflicted.isEmpty()) {
      throw new RE("Invalid expression: %s; %s used as both scalar and array variables", expression, conflicted);
    }
  }

}

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Rewrite the expression to avoid the unsupported apply function, or pre-flatten it manually.
  2. Upgrade Druid so the rewrite logic supports the apply function used.
  3. If extending the engine, add a case for the new ApplyFunction in liftApplyLambda.

Example fix

// before
Expr e = Parser.parse("fold((x) -> x + 1, arr, custom_apply_fn)", null, true /* flatten */);
// after — use a supported fold form or flatten=false
Expr e = Parser.parse("map((x) -> x + 1, arr)", null);
Defensive patterns

Strategy: fallback

Validate before calling

// avoid flattening expressions containing unsupported apply functions
boolean hasApply = exprString.contains("fold(") || exprString.contains("map(");

Try / catch

try { e = Parser.parse(in, macroTable, true); } catch (RuntimeException re) { if (re.getMessage().contains("Unable to transform apply function")) { e = Parser.parse(in, macroTable, false); } }

Prevention

When it happens

Trigger: Expression flattening/rewrite (Parser with flatten=true or rewriteUnappliedSubExpressions) encountering apply-lambda expressions using fold variants other than the handled ones — typically with custom or newer ApplyFunction implementations.

Common situations: Using lambda expressions (fold/map-style apply) in contexts that trigger the rewriting pass (e.g. expressions requiring flattening); custom extensions adding new ApplyFunction types not registered in the lift logic; Druid version mismatches where a newer function hits older rewrite code.

Related errors


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