apache/druid · error · RE

Unrecognized unary operator %s

Error message

Unrecognized unary operator %s

What it means

During ANTLR-based expression parsing, ExprListenerImpl.exitUnaryOpExpr maps the parse-tree operator token to UnaryMinusExpr or UnaryNotExpr. Any other unary operator token reaches the default branch and throws a RuntimeException ('Unrecognized unary operator %s'), indicating the parser grammar and the listener are out of sync or the input produced an unexpected token.

Source

Thrown at processing/src/main/java/org/apache/druid/math/expr/ExprListenerImpl.java:83

  Expr getAST()
  {
    return (Expr) nodes.get(rootNodeKey);
  }

  @Override
  public void exitUnaryOpExpr(ExprParser.UnaryOpExprContext ctx)
  {
    int opCode = ((TerminalNode) ctx.getChild(0)).getSymbol().getType();
    switch (opCode) {
      case ExprParser.MINUS:
        nodes.put(ctx, new UnaryMinusExpr(ctx.getChild(0).getText(), (Expr) nodes.get(ctx.getChild(1))));
        break;
      case ExprParser.NOT:
        nodes.put(ctx, new UnaryNotExpr(ctx.getChild(0).getText(), (Expr) nodes.get(ctx.getChild(1))));
        break;
      default:
        throw new RE("Unrecognized unary operator %s", ctx.getChild(0).getText());
    }
  }

  @Override
  public void exitApplyFunctionExpr(ExprParser.ApplyFunctionExprContext ctx)
  {
    String fnName = ctx.getChild(0).getText();
    // Built-in functions.
    final ApplyFunction function = Parser.getApplyFunction(fnName);
    if (function == null) {
      throw new RE("function '%s' is not defined.", fnName);
    }

    nodes.put(
        ctx,
        new ApplyFunctionExpr(function, fnName, (LambdaExpr) nodes.get(ctx.lambda()), (List<Expr>) nodes.get(ctx.fnArgs()))
    );
  }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Fix the expression string to use supported unary operators: '-' for negation and 'NOT' for logical not
  2. Replace '!' with 'NOT' or restructure the condition
  3. If the token looks valid, upgrade Druid so grammar and listener match

Example fix

// before
"!flag"
// after
"NOT flag"
Defensive patterns

Strategy: validation

Validate before calling

// validate expression text before parsing
String trimmed = exprStr.trim();
if (trimmed.matches("^!.*") || trimmed.startsWith("~")) {
  throw new IllegalArgumentException("unsupported unary operator in: " + exprStr);
}

Try / catch

try {
  expr = Expr.parse(exprStr);
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Unrecognized unary operator")) {
    throw new IllegalArgumentException("Invalid expression: " + exprStr, e);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Parsing an expression whose unary operator token isn't '-' or 'NOT', typically via Expr.parse / Parser.parse with malformed or nonstandard unary syntax.

Common situations: Hand-written expressions with invalid unary syntax like '!' (instead of NOT) or stray symbols; grammar/parser version skew after a Druid upgrade; programmatic query builders emitting unsupported tokens.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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