apache/druid · error · DruidException

escape must be null or a single character

Error message

escape must be null or a single character

What it means

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.

Source

Thrown at processing/src/main/java/org/apache/druid/query/expression/LikeExprMacro.java:61

  @Override
  public Expr apply(final List<Expr> args)
  {
    validationHelperCheckAnyOfArgumentCount(args, 2, 3);

    final Expr arg = args.get(0);
    final Expr patternExpr = args.get(1);
    final Expr escapeExpr = args.size() > 2 ? args.get(2) : null;

    validationHelperCheckArgIsLiteral(patternExpr, "pattern");
    if (escapeExpr != null) {
      validationHelperCheckArgIsLiteral(escapeExpr, "escape");
    }

    final String escape = escapeExpr == null ? null : (String) escapeExpr.getLiteralValue();
    final Character escapeChar;

    if (escape != null && escape.length() != 1) {
      throw validationFailed("escape must be null or a single character");
    } else {
      escapeChar = escape == null ? null : escape.charAt(0);
    }

    final LikeDimFilter.LikeMatcher likeMatcher = LikeDimFilter.LikeMatcher.from(
        (String) patternExpr.getLiteralValue(),
        escapeChar
    );

    class LikeExtractExpr extends ExprMacroTable.BaseScalarMacroFunctionExpr
    {
      private LikeExtractExpr(List<Expr> args)
      {
        super(LikeExprMacro.this, args);
      }

      @Nonnull
      @Override

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Ensure the escape literal is exactly one character, e.g. LIKE(col, 'a!%b', '!').
  2. Omit the escape argument entirely instead of passing an empty string.
  3. Check SQL string-literal escaping so a single backslash in the pattern becomes one character, not two, in the actual value.

Example fix

-- before
SELECT LIKE(col, '100\\%', '\\\\') FROM t
-- after
SELECT LIKE(col, '100!%', '!') FROM t
Defensive patterns

Strategy: validation

Validate before calling

// Java
if (escape != null && escape.length() != 1) { throw new IllegalArgumentException("escape must be exactly one character"); }

Type guard

static Character toEscapeChar(String escape) {
  return (escape == null || escape.length() == 1) ? (escape == null ? null : escape.charAt(0)) : null;
}

Try / catch

try {
  return runDruidQuery(query);
} catch (ExpressionValidationException e) {
  if (e.getMessage().contains("escape must be null or a single character")) {
    throw new UserInputException("LIKE escape must be one character or omitted");
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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/e0d7034e2808d62a. Report an issue: GitHub.