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
@OverrideView on GitHub (pinned to 9b90983fd2)
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.
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
- 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').
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
- Invalid expression: %s; %s used as both scalar and array var
- rank must be a number
- subnet arg has an invalid format: %s
- subnet arg has an invalid format: %s
- second argument must be a registered lookup name
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/e0d7034e2808d62a.
Report an issue: GitHub.