apple/pkl · error
errorInRegexReplacement
errorInRegexReplacement
Error message
errorInRegexReplacement
What it means
String.replaceAll(regex, replacement) wraps Java's Matcher.replaceAll; if the replacement string is itself invalid as a Java/Pkl regex replacement template, the underlying IndexOutOfBoundsException or IllegalArgumentException is rethrown as errorInRegexReplacement with the pattern, the offending replacement, and the underlying message. The pattern itself compiles fine — the failure is in the replacement template.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/stdlib/base/StringNodes.java:538
var idx = findOffset(self, function);
return substringUntil(self, idx);
}
}
public abstract static class replaceAll extends ExternalMethod2Node {
@TruffleBoundary
@Specialization
protected String eval(String self, String pattern, String replacement) {
return self.replace(pattern, replacement);
}
@TruffleBoundary
@Specialization
protected String eval(String self, VmRegex regex, String replacement) {
try {
return regex.matcher(self).replaceAll(replacement);
} catch (IndexOutOfBoundsException | IllegalArgumentException e) {
throw exceptionBuilder()
.evalError(
"errorInRegexReplacement",
regex.getPattern().toString(),
replacement,
e.getMessage())
.build();
}
}
}
public abstract static class replaceFirst extends ExternalMethod2Node {
@TruffleBoundary
@Specialization
protected String eval(String self, String pattern, String replacement) {
int idx = self.indexOf(pattern);
if (idx == -1) return self;
return self.substring(0, idx) + replacement + self.substring(idx + pattern.length());
}View on GitHub (pinned to f3efcbfc9b)
Solutions
- Escape `$` as `$$` and `\` as `\\` in the replacement string before calling replaceAll.
- When the replacement is plain text, use replaceAll(literalPattern, replacement) with a String pattern instead of a Regex, which does literal replacement.
- Sanitize dynamic replacements, e.g. replacement.replaceAll("\\$", "$$").replaceAll("\\\\", "\\\\\\\\").
- If you need capture groups, verify the regex actually defines the group referenced by $n (n <= group count).
Example fix
// before
s.replaceAll(Regex("price"), "cost: $5") // $5 = invalid group ref
// after
s.replaceAll(Regex("price"), "cost: $$5") // or use a literal String pattern Defensive patterns
Strategy: validation
Validate before calling
// Pkl: escape replacement specials before use
function escapeReplacement(r: String): String =
r.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\$", "$$")
// call site
s.replaceAll(Regex("price"), escapeReplacement(userText)) Type guard
function isSafeReplacement(r: String): Boolean = !r.contains("$") && !r.endsWith("\\") Try / catch
try { s.replaceAll(regex, repl) } catch (e: PklError) { log(e.message); s } Prevention
- Escape $ as $$ and backslash as \\ in dynamic replacements
- Use the String (literal) overload of replaceAll for plain-text replacements
- Verify $n references match existing regex groups
- Never substitute raw user/path input into regex replacement templates unescaped
When it happens
Trigger: Replacement strings containing a bare `$` (dangling group reference like "$" or "$1" with no group 1), a `$` followed by an invalid character, or a trailing lone `\` (invalid escape sequence), e.g. "prices from $5" or Windows-style paths used as replacement text.
Common situations: Substituting user-provided text (paths, currency amounts, shell snippets) into regex replacements; templating config values that literally contain $ or \; generating code/config where `$` is currency, not a capture group.
Related errors
- doesNotContainRegexMatch
- Cannot convert pkl.base#String `%s` to java.lang.Character b
- Failed to convert `pkl.base#String` to `java.util.regex.Patt
- Values of type `Regex` cannot be rendered as Properties. Val
- invalidRegexSyntax
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/3bc68e913c3d83b7.
Report an issue: GitHub.