oracle/graal · error · UnsupportedRegexException
UTF-16 range with surrogate values as upper or lower bound
Error message
UTF-16 range with surrogate values as upper or lower bound
What it means
Thrown by the OracleDB-flavor parser when a character-class range has one bound inside the UTF-16 surrogate block (U+D800..U+DFFF). OracleDB regexes match over UTF-16 code units, but TRegex internally works on code points and treats unpaired surrogates as invalid bounds; if lo or hi falls inside the surrogate range (and the range is not the already-handled broken/pair cases above), it throws UnsupportedRegexException.
Source
Thrown at regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/flavor/oracledb/OracleDBRegexParser.java:304
*
* This function transforms a given range to match LXR's behavior in case-sensitive mode.
*/
private CodePointSet utf16RangeQuirkTransform(ClassSetContents contents) {
int lo = contents.getRangeLo();
int hi = contents.getRangeHi();
if (contents.isBrokenRange()) {
assert lo > Character.MAX_VALUE && hi > Character.MAX_SURROGATE && hi <= Character.MAX_VALUE && Character.highSurrogate(lo) <= hi;
if (hi + 1 == lo) {
return CodePointSet.createNoDedup(Character.MAX_SURROGATE + 1, Character.MAX_CODE_POINT);
} else {
return CodePointSet.createNoDedup(Character.MAX_SURROGATE + 1, hi, lo, Character.MAX_CODE_POINT);
}
}
if (hi < Character.MIN_SURROGATE) {
return contents.getCodePointSet();
}
if (Character.MIN_SURROGATE <= lo && lo <= Character.MAX_SURROGATE || hi <= Character.MAX_SURROGATE) {
throw new UnsupportedRegexException("UTF-16 range with surrogate values as upper or lower bound");
}
if (lo < Character.MIN_SURROGATE) {
if (hi == Character.MAX_VALUE) {
// range contains the surrogate range => surrogate pairs will match as well.
return CodePointSet.create(lo, Character.MAX_CODE_POINT);
} else if (hi < Character.MAX_VALUE) {
// range contains the surrogate range => surrogate pairs will match as well.
return CodePointSet.create(lo, hi, Character.MAX_VALUE + 1, Character.MAX_CODE_POINT);
} else {
// lower bound is less than surrogate range and upper bound is a surrogate
// pair => exclude the range from surrogate range to 0xffff.
return CodePointSet.create(lo, Character.MIN_SURROGATE - 1, Character.MAX_VALUE + 1, hi);
}
} else {
if (hi <= Character.MAX_VALUE || lo > Character.MAX_VALUE) {
// either both values are encoded as a surrogate pair or both are single
// char values
return contents.getCodePointSet();View on GitHub (pinned to a66e9ccd1d)
Solutions
- Exclude the surrogate block from class ranges: use bounds below U+D800 or at/above U+E000, e.g. [\u1000-\uD7FF] or [\uE000-\uFFFF]
- To match supplementary (astral) characters, allow surrogate pairs by extending the upper bound to U+10FFFF via the pair-matching forms the parser supports (range ending at Character.MAX_VALUE), rather than naming surrogate units directly
- Validate generated ranges programmatically: reject any bound where 0xD800 <= cp <= 0xDFFF
Example fix
// before (OracleDB flavor) "[\\uD800-\\uDFFF]" // surrogate bounds // after "[\\uE000-\\uFFFF]" // avoid the surrogate block
Defensive patterns
Strategy: validation
Validate before calling
boolean rangeHasSurrogateBound(String pattern) {
java.util.regex.Matcher m = java.util.regex.Pattern.compile("\\\\u(D800|DB7F|DB80|DBFF|DC00|DF7F|DF80|DFFF)").matcher(pattern);
return m.find();
}
// stronger: parse class ranges and reject any bound cp where 0xD800 <= cp <= 0xDFFF Try / catch
try {
RegexObject re = compileOracleDB(pattern);
} catch (UnsupportedRegexException e) {
// rewrite ranges to exclude U+D800..U+DFFF bounds, then recompile
} Prevention
- Never use surrogate code points as range endpoints in OracleDB-flavor classes
- Generate ranges from code point data with an assert outside 0xD800..0xDFFF
When it happens
Trigger: Compiling an OracleDB-flavor class like [\uD800-\uDBFF], [\uDC00-\uDFFF], or [\u1000-\uD800] where a range endpoint is a surrogate code unit. The checks Character.MIN_SURROGATE <= lo <= MAX_SURROGATE or hi <= MAX_SURROGATE fire and throw.
Common situations: Patterns generated from code point arithmetic or \uXXXX literals intended to match astral characters by their surrogate halves; porting patterns that attempt to match raw surrogate units; ranges copied from Unicode charts that accidentally include the surrogate block.
Related errors
- Unsupported Unicode character property escape
- Binary property %s cannot appear to the left of '=' in a Uni
- Unsupported Unicode character property '%s'
- Unsupported Unicode %s '%s'
- Character class maximum nesting level exceeded
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/ac4684cc07e74ee9.
Report an issue: GitHub.