{"record":{"id":"e0d7034e2808d62a","repo":"apache/druid","slug":"escape-must-be-null-or-a-single-character-e0d703","errorCode":null,"errorMessage":"escape must be null or a single character","messagePattern":"escape must be null or a single character","errorType":"validation","errorClass":"DruidException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/expression/LikeExprMacro.java","lineNumber":61,"sourceCode":"  @Override\n  public Expr apply(final List<Expr> args)\n  {\n    validationHelperCheckAnyOfArgumentCount(args, 2, 3);\n\n    final Expr arg = args.get(0);\n    final Expr patternExpr = args.get(1);\n    final Expr escapeExpr = args.size() > 2 ? args.get(2) : null;\n\n    validationHelperCheckArgIsLiteral(patternExpr, \"pattern\");\n    if (escapeExpr != null) {\n      validationHelperCheckArgIsLiteral(escapeExpr, \"escape\");\n    }\n\n    final String escape = escapeExpr == null ? null : (String) escapeExpr.getLiteralValue();\n    final Character escapeChar;\n\n    if (escape != null && escape.length() != 1) {\n      throw validationFailed(\"escape must be null or a single character\");\n    } else {\n      escapeChar = escape == null ? null : escape.charAt(0);\n    }\n\n    final LikeDimFilter.LikeMatcher likeMatcher = LikeDimFilter.LikeMatcher.from(\n        (String) patternExpr.getLiteralValue(),\n        escapeChar\n    );\n\n    class LikeExtractExpr extends ExprMacroTable.BaseScalarMacroFunctionExpr\n    {\n      private LikeExtractExpr(List<Expr> args)\n      {\n        super(LikeExprMacro.this, args);\n      }\n\n      @Nonnull\n      @Override","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/expression/LikeExprMacro.java#L43-L79","documentation":"The LIKE expression macro's optional third argument (escape) must be null or exactly one character, since it is converted to a Java Character for LikeMatcher. Druid throws a validation failure at expression compilation when a longer string is supplied, because multi-character escape sequences have no meaning in LIKE pattern matching.","triggerScenarios":"Calling LIKE(expr, pattern, '<escape>') where the escape literal has length != 1, e.g. LIKE(col, 'a\\\\%b', '\\\\\\\\') producing a two-character string, or passing an empty string '' as the escape.","commonSituations":"Escaping confusion in SQL string literals (double backslashes) that inflate the character count; passing '' intending 'no escape'; templating tools that append unwanted whitespace to the escape argument.","solutions":["Ensure the escape literal is exactly one character, e.g. LIKE(col, 'a!%b', '!').","Omit the escape argument entirely instead of passing an empty string.","Check SQL string-literal escaping so a single backslash in the pattern becomes one character, not two, in the actual value."],"exampleFix":"-- before\nSELECT LIKE(col, '100\\\\%', '\\\\\\\\') FROM t\n-- after\nSELECT LIKE(col, '100!%', '!') FROM t","handlingStrategy":"validation","validationCode":"// Java\nif (escape != null && escape.length() != 1) { throw new IllegalArgumentException(\"escape must be exactly one character\"); }","typeGuard":"static Character toEscapeChar(String escape) {\n  return (escape == null || escape.length() == 1) ? (escape == null ? null : escape.charAt(0)) : null;\n}","tryCatchPattern":"try {\n  return runDruidQuery(query);\n} catch (ExpressionValidationException e) {\n  if (e.getMessage().contains(\"escape must be null or a single character\")) {\n    throw new UserInputException(\"LIKE escape must be one character or omitted\");\n  }\n  throw e;\n}","preventionTips":["Omit the escape argument unless a custom escape is truly needed.","Double-check SQL string-literal escaping so the runtime value is one char.","Choose escape characters that never appear in data (e.g. '\\u0001')."],"tags":["druid","expression","like","validation"],"backgroundTag":"invalid-argument-value","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"}