apache/druid · error · DruidException

pattern must be a string literal

Error message

pattern must be a string literal

What it means

regexp_replace's RegexpReplaceExpr constructor requires the pattern argument to be a string literal (or an explicit literal NULL, which is tolerated and disables matching). Any other pattern expression fails validation because patterns are precompiled at parse time.

Source

Thrown at processing/src/main/java/org/apache/druid/query/expression/RegexpReplaceExprMacro.java:88

  /**
   * Expr when pattern and replacement are literals.
   */
  class RegexpReplaceExpr extends BaseRegexpReplaceExpr
  {
    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)
    {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Provide the pattern as a quoted string literal
  2. If a NULL pattern is intended, make it an explicit literal NULL (this is accepted)
  3. Restructure the query so pattern matching happens outside the expression

Example fix

// before
REGEXP_REPLACE(col, pat_col, 'X')
// after
REGEXP_REPLACE(col, '[aeiou]', 'X')
Defensive patterns

Strategy: validation

Validate before calling

boolean ok = ExprUtils.isStringLiteral(patternExpr)
    || (patternExpr.isLiteral() && patternExpr.getLiteralValue() == null);
if (!ok) {
  throw new IllegalArgumentException("pattern 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 pattern invalid: %s", e.getMessage());
  throw e;
}

Prevention

When it happens

Trigger: REGEXP_REPLACE(expr, pattern, replacement) where pattern is a column reference, computed expression, or non-string non-null literal.

Common situations: Dynamic regex patterns sourced from data; forgetting quotes so the pattern parses as an identifier; generated queries with concatenated pattern fields.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/3adcd3c5705ab9b0. Report an issue: GitHub.