apache/druid · error · DruidException
replacement must be a string literal
Error message
replacement must be a string literal
What it means
regexp_replace requires the replacement argument (third argument) to be a string literal, or an explicit literal NULL. Non-literal replacements cannot be embedded in the precompiled replace expression, so validation fails.
Source
Thrown at processing/src/main/java/org/apache/druid/query/expression/RegexpReplaceExprMacro.java:93
private final Expr arg;
private final Pattern pattern;
private final String replacement;
private RegexpReplaceExpr(List<Expr> args)
{
super(args);
final Expr patternExpr = args.get(1);
final Expr replacementExpr = args.get(2);
if (!ExprUtils.isStringLiteral(patternExpr)
&& !(patternExpr.isLiteral() && patternExpr.getLiteralValue() == null)) {
throw validationFailed("pattern must be a string literal");
}
if (!ExprUtils.isStringLiteral(replacementExpr)
&& !(replacementExpr.isLiteral() && replacementExpr.getLiteralValue() == null)) {
throw validationFailed("replacement must be a string literal");
}
final String patternString = (String) patternExpr.getLiteralValue();
this.arg = args.get(0);
this.pattern = patternString != null ? RegexpExprUtils.compilePattern(patternString, FN_NAME) : null;
this.replacement = (String) replacementExpr.getLiteralValue();
}
@Nonnull
@Override
public ExprEval<?> eval(final ObjectBinding bindings)
{
if (pattern == null || replacement == null) {
return ExprEval.ofString(null);
}
final String s = arg.eval(bindings).asString();View on GitHub (pinned to 9b90983fd2)
Solutions
- Inline the replacement as a quoted string literal
- Use literal NULL only if you intend null replacement semantics
- Perform substitution with a different expression (e.g. CONCAT) if the replacement must be dynamic
Example fix
// before REGEXP_REPLACE(col, '[aeiou]', repl_col) // after REGEXP_REPLACE(col, '[aeiou]', '-')
Defensive patterns
Strategy: validation
Validate before calling
boolean ok = ExprUtils.isStringLiteral(replacementExpr)
|| (replacementExpr.isLiteral() && replacementExpr.getLiteralValue() == null);
if (!ok) {
throw new IllegalArgumentException("replacement must be a string literal");
} Type guard
static boolean isStringOrNullLiteral(Expr e) {
return ExprUtils.isStringLiteral(e) || (e.isLiteral() && e.getLiteralValue() == null);
} Try / catch
try {
return macro.apply(args);
} catch (ExpressionValidationException e) {
log.error("regexp_replace replacement invalid: %s", e.getMessage());
throw e;
} Prevention
- Inline replacement strings
- Do not reference columns in the replacement position
- Add expression validation to query-submission pipelines
When it happens
Trigger: REGEXP_REPLACE(expr, 'pattern', repl) where repl is a column, expression, or non-string non-null literal.
Common situations: Replacement strings pulled from other columns; passing numbers or booleans as the replacement; templated query generation injecting non-literal values.
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
- pattern must be a string literal
- index must be a numeric literal
- pattern must be a STRING literal
- pattern must be a string literal
- Incorrect Regex: %s . No match found.
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/0ac8fe372b4b5275.
Report an issue: GitHub.