{"record":{"id":"476928c7c1f3c7c5","repo":"apache/druid","slug":"unrecognized-binary-operator-s","errorCode":null,"errorMessage":"Unrecognized binary operator %s","messagePattern":"Unrecognized binary operator (.+?)","errorType":"validation","errorClass":"RE","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/math/expr/ExprListenerImpl.java","lineNumber":140,"sourceCode":"            new BinPlusExpr(\n                ctx.getChild(1).getText(),\n                (Expr) nodes.get(ctx.getChild(0)),\n                (Expr) nodes.get(ctx.getChild(2))\n            )\n        );\n        break;\n      case ExprParser.MINUS:\n        nodes.put(\n            ctx,\n            new BinMinusExpr(\n                ctx.getChild(1).getText(),\n                (Expr) nodes.get(ctx.getChild(0)),\n                (Expr) nodes.get(ctx.getChild(2))\n            )\n        );\n        break;\n      default:\n        throw new RE(\"Unrecognized binary operator %s\", ctx.getChild(1).getText());\n    }\n  }\n\n  @Override\n  public void exitLongExpr(ExprParser.LongExprContext ctx)\n  {\n    nodes.put(\n        ctx,\n        new BigIntegerExpr(new BigInteger(ctx.getText()))\n    );\n  }\n\n  @Override\n  public void exitLogicalAndOrExpr(ExprParser.LogicalAndOrExprContext ctx)\n  {\n    int opCode = ((TerminalNode) ctx.getChild(1)).getSymbol().getType();\n    switch (opCode) {\n      case ExprParser.AND:","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/math/expr/ExprListenerImpl.java#L122-L158","documentation":"ExprListenerImpl.exitAddSubExpr maps '+'/'-' (add/sub parse contexts) tokens to BinaryPlusExpr/BinaryMinusExpr. An unexpected operator token in that context falls to the default branch and throws 'Unrecognized binary operator %s', meaning grammar and listener disagree or the input is malformed.","triggerScenarios":"Parsing an expression where the add/sub rule sees a token other than '+' or '-', e.g. corrupt expression text or a grammar/listener mismatch after modifying the Expr.g4 grammar.","commonSituations":"Programmatically generated expression strings with bad operator tokens; custom Druid builds where the ANTLR grammar was extended but exitAddSubExpr wasn't updated; garbled query text from upstream tools.","solutions":["Fix the expression string to use '+' or '-' in additive positions","Regenerate the ANTLR parser after any grammar change and add the missing case in exitAddSubExpr","Upgrade to a stock Druid version with consistent grammar/listener"],"exampleFix":"// before\n\"a ~ b\" in additive context\n// after\n\"a + b\"","handlingStrategy":"validation","validationCode":"// ensure only + or - appear in additive positions of generated expressions\nif (!generatedExpr.matches(\"[a-zA-Z0-9_+\\- ()]*\")) {\n  throw new IllegalArgumentException(\"invalid operator in expression: \" + generatedExpr);\n}","typeGuard":null,"tryCatchPattern":"try {\n  expr = Expr.parse(exprStr);\n} catch (RuntimeException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Unrecognized binary operator\")) {\n    throw new IllegalArgumentException(\"Invalid expression: \" + exprStr, e);\n  } else { throw e; }\n}","preventionTips":["Only use '+'/'-' for addition/subtraction in native expressions","Validate programmatically generated expressions","Keep ANTLR grammar regenerated after edits"],"tags":["expressions","parsing","grammar"],"backgroundTag":"invalid-argument-format","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}