prestodb/presto · error · PrestoException
INVALID_FUNCTION_ARGUMENT
INVALID_FUNCTION_ARGUMENT
Error message
Illegal replacement sequence:
What it means
regexp_replace wraps RE2/J's Matcher.replaceAll, which throws IllegalArgumentException or IndexOutOfBoundsException when the replacement string uses invalid group references or illegal escape/backreference sequences (e.g., a lone '$' or '$9' when fewer groups exist). Re2JRegexp translates that into an INVALID_FUNCTION_ARGUMENT PrestoException naming the offending replacement string.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/type/Re2JRegexp.java:86
}
else {
re2jPatternWithoutDotStartPrefix = re2jPattern;
}
}
public boolean matches(Slice source)
{
return re2jPatternWithoutDotStartPrefix.find(source);
}
public Slice replace(Slice source, Slice replacement)
{
Matcher matcher = re2jPattern.matcher(source);
try {
return matcher.replaceAll(replacement);
}
catch (IndexOutOfBoundsException | IllegalArgumentException e) {
throw new PrestoException(INVALID_FUNCTION_ARGUMENT, "Illegal replacement sequence: " + replacement.toStringUtf8());
}
}
public Block extractAll(Slice source, long groupIndex)
{
Matcher matcher = re2jPattern.matcher(source);
int group = toIntExact(groupIndex);
validateGroup(group, matcher.groupCount());
BlockBuilder blockBuilder = VARCHAR.createBlockBuilder(null, 32);
while (true) {
if (!matcher.find()) {
break;
}
Slice searchedGroup = matcher.group(group);
if (searchedGroup == null) {
blockBuilder.appendNull();View on GitHub (pinned to 55bb57d202)
Solutions
- Escape literal '$' in the replacement as '$$' and literal backslashes as '\\'.
- Ensure every $n reference is <= the number of capture groups in the pattern (count your parentheses).
- If the replacement is user-supplied, sanitize it (e.g., Matcher.quoteReplacement semantics) before passing it to regexp_replace.
Example fix
// before regexp_replace(name, '(\w+) (\w+)', '$1$3') // after regexp_replace(name, '(\w+) (\w+)', '$2 $1')
Defensive patterns
Strategy: validation
Validate before calling
// Java-side sanity check before building the replacement
static String safeReplacement(String repl) {
// escape literal $ and \ so RE2/J treats them as literals
return repl.replace("\\", "\\\\").replace("$", "$$");
} Type guard
boolean hasValidGroupRefs(String replacement, int groupCount) {
java.util.regex.Matcher m = java.util.regex.Pattern.compile("\\$(\\d+)").matcher(replacement);
while (m.find()) {
if (Integer.parseInt(m.group(1)) > groupCount) return false;
}
return true;
} Try / catch
try {
return regexpReplace(pattern, source, replacement);
} catch (PrestoException e) {
if (INVALID_FUNCTION_ARGUMENT.equals(e.getErrorCode()) && e.getMessage().startsWith("Illegal replacement sequence")) {
return regexpReplace(pattern, source, escapedReplacement);
}
throw e;
} Prevention
- Escape '$' as '$$' and '\' as '\\' whenever replacement text can contain literals.
- Verify each $n backreference is within the pattern's capture-group count.
- Sanitize user-supplied replacement strings before passing them into regexp_replace.
When it happens
Trigger: Calling regexp_replace(pattern, source, replacement) where the replacement Slice contains an invalid group reference (e.g., '$' followed by a digit beyond the group count, unescaped '$', or malformed \ escape) that RE2/J rejects at replace time.
Common situations: Dollar signs in literal replacement text that must be escaped as '$$'; copy-pasted regexes from Java/PCRE engines with group indices larger than the pattern defines; dynamic replacements built from user input.
Related errors
- GENERIC_INTERNAL_ERROR
- Timeout is negative
- INVALID_FUNCTION_ARGUMENT
- INVALID_FUNCTION_ARGUMENT
- GENERIC_INTERNAL_ERROR
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/49e32bba797581a8.
Report an issue: GitHub.