oracle/graal · error · UnsupportedRegexException
nested quantifier in regular expression
Error message
nested quantifier in regular expression
What it means
Thrown by the OracleDB-flavor parser when a quantifier token immediately follows another quantifier token. Oracle's SQL regex dialect does not allow stacked quantifiers (no possessive or lazy modifiers on quantifiers), so prevKind == Token.Kind.quantifier triggers UnsupportedRegexException(NESTED_QUANTIFIER).
Source
Thrown at regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/flavor/oracledb/OracleDBRegexParser.java:178
astBuilder.addDollar();
astBuilder.nextSequence();
astBuilder.pushLookAheadAssertion(false);
astBuilder.addCharClass(CodePointSet.create('\n'));
if (token.kind == Token.Kind.Z || !flags.isMultiline()) {
astBuilder.addDollar();
}
astBuilder.popGroup();
if (token.kind == Token.Kind.dollar && flags.isMultiline()) {
astBuilder.addPositionAssertion(PositionAssertion.Type.MATCH_END);
}
astBuilder.popGroup();
break;
case backReference:
astBuilder.addBackReference((Token.BackReference) token, flags.isIgnoreCase());
break;
case quantifier:
if (prevKind == Token.Kind.quantifier) {
throw new UnsupportedRegexException(OracleDBErrorMessages.NESTED_QUANTIFIER);
}
if (astBuilder.getCurTerm() == null || prevKind == Token.Kind.captureGroupBegin) {
// quantifiers without target are ignored
break;
}
astBuilder.addQuantifier((Token.Quantifier) token);
break;
case alternation:
astBuilder.nextSequence();
break;
case captureGroupBegin:
if (lexer.numberOfCaptureGroupsSoFar() <= 10) {
// oracledb only tracks capture groups 0 - 9
astBuilder.pushCaptureGroup(token);
} else {
astBuilder.pushGroup(token);
}
break;View on GitHub (pinned to a66e9ccd1d)
Solutions
- Replace the two-letter quantifier forms with the plain greedy form: 'a*?' -> 'a*', 'a++' -> 'a+'
- Wrap the inner quantified expression in a group if you need repetition of a repetition: 'a**' is invalid, '(a*)*' is the closest legal form (mind the semantics)
- Strip lazy/possessive suffixes when translating patterns from other dialects into OracleDB flavor
Example fix
-- before (OracleDB flavor) a.*?b -- lazy quantifier -- after a.*b -- greedy quantifier
Defensive patterns
Strategy: try-catch
Validate before calling
boolean hasStackedQuantifiers(String pattern) {
return java.util.regex.Pattern.compile("([*+?]|\\{[0-9]+(,[0-9]*)?\\})([*+?]|\\{)").matcher(pattern).find();
} Try / catch
try {
RegexObject re = compileOracleDB(pattern);
} catch (UnsupportedRegexException e) {
if (e.getReason().contains("nested quantifier")) {
// drop lazy/possessive second quantifier and retry once
} else { throw e; }
} Prevention
- When porting to OracleDB flavor, remove '*?', '+?', '?+', '*+', '++' forms
- Validate SQL-bound regexes in application code before sending them to REGEXP_LIKE-style calls
When it happens
Trigger: Compiling an OracleDB-flavor regex such as 'a**', 'a++', 'a*?', '(ab)+?' or 'a{2,3}*' — any pattern where a quantifier directly follows another quantifier token. The parser sees the second quantifier with prevKind == quantifier and throws.
Common situations: Porting PCRE/Java patterns with lazy ('*?') or possessive ('*+', '++') quantifiers into Oracle Database regex semantics (e.g. via a GraalVM-based SQL engine using TRegex's OracleDB flavor); JS/Python-style regexes pasted into SQL REGEXP_LIKE calls.
Related errors
- possessive quantifiers are not supported
- possessive quantifiers are not supported
- UTF-16 range with surrogate values as upper or lower bound
- Bad pattern: {}
- Failed to parse experiment {experimentId} in {resource}: {me
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/7a4d5eac6fe4cbe1.
Report an issue: GitHub.