oracle/graal · error · UnsupportedRegexException
too many quantifiers
Error message
too many quantifiers
What it means
Thrown in ASTStepVisitor.visit when the quantifier index returned by needsMaintainGuard() exceeds Short.MAX_VALUE (32767). Quantifier counters are indexed by a short in the compact TransitionGuard/TransitionOp encoding, so a regex with more than 32767 distinct tracked quantifiers cannot be represented. The guard id is also used to emit a 'maintain' transition op for loop quantifiers on the current path.
Source
Thrown at regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/ASTStepVisitor.java:162
setMatchedConditionGroups(stepCur.getMatchedConditionGroups());
root = (Term) stepCur.getRoot();
run(root);
}
return stepRoot;
}
@Override
protected void visit(RegexASTNode target) {
assert allGuardsAllowedInDFA(getTransitionGuardsOnPath());
ASTSuccessor successor = new ASTSuccessor();
long[] guards = getTransitionGuardsOnPath();
operationsBuilder.clear();
constraintsBuilder.clear();
int id = needsMaintainGuard();
if (id != -1) {
if (id > Short.MAX_VALUE) {
throw new UnsupportedRegexException("too many quantifiers");
}
operationsBuilder.add(TransitionOp.create(id, 0, 0, TransitionOp.maintain));
}
for (long guard : guards) {
switch (TransitionGuard.getKind(guard)) {
case countLtMax -> constraintsBuilder.add(TransitionConstraint.create(getQuantifierIndex(guard), 0, TransitionConstraint.anyLtMax));
case countGeMin -> constraintsBuilder.add(TransitionConstraint.create(getQuantifierIndex(guard), 0, TransitionConstraint.anyGeMin));
case countLtMin -> constraintsBuilder.add(TransitionConstraint.create(getQuantifierIndex(guard), 0, TransitionConstraint.anyLtMin));
case countInc -> operationsBuilder.add(TransitionOp.create(getQuantifierIndex(guard), 0, 0, TransitionOp.inc));
case countSet1 -> operationsBuilder.add(TransitionOp.create(getQuantifierIndex(guard), 0, 0, TransitionOp.set1));
}
}
ASTTransition transition = new ASTTransition(ast.getLanguage(), constraintsBuilder.toArray(), operationsBuilder.toArray());
transition.setGroupBoundaries(getGroupBoundaries());
TBitSet matchedConditionGroups = getCurrentMatchedConditionGroups();
transition.setMatchedConditionGroups(matchedConditionGroups);View on GitHub (pinned to a66e9ccd1d)
Solutions
- Reduce the number of quantified sub-expressions below 32768 by factoring repeated parts into loops or character classes.
- Split the pattern into several smaller regexes and combine matches in code.
- If the pattern is generated, audit the generator for accidental per-character quantifiers (e.g. emitting x? for every optional token).
Example fix
// before
StringBuilder sb = new StringBuilder();
for (String w : words) sb.append(Pattern.quote(w)).append("{0,1}"); // thousands of quantifiers
// after
String alt = words.stream().map(Pattern::quote).collect(Collectors.joining("|"));
String pattern = "(?:" + alt + ")"; // one alternation, no per-word quantifiers Defensive patterns
Strategy: validation
Validate before calling
int quantifiers = 0; boolean esc = false; for (char c : pattern.toCharArray()) { if (esc) { esc = false; continue; } if (c == '\\') { esc = true; } else if (c == '{' || c == '*' || c == '+' || c == '?') quantifiers++; } if (quantifiers > 32_000) throw new IllegalArgumentException("too many quantifiers for TRegex (max 32767)"); Type guard
null
Try / catch
try { compile(pattern); } catch (UnsupportedRegexException e) { if (e.getMessage().contains("too many quantifiers")) { /* split pattern or reject */ } } Prevention
- Audit regex generators for per-token quantifier emission.
- Count quantifier metacharacters before compiling generated patterns.
- Split large generated patterns into batches.
When it happens
Trigger: Compiling a pattern that declares more than 32767 counted/bounded quantifiers (e.g. machine-generated regex with tens of thousands of a{1,2}-style terms), so the id assigned to the maintained quantifier no longer fits in a short.
Common situations: Programmatically generated regexes from data (token alternations, fuzzy-match expansions, generated test patterns); converting a large grammar or wildcard expression into one regex.
Related errors
- DFA transition size explosion
- Regex with overlapping bounded quantifier (after look-ahead
- too many transitions
- ASTSuccessor explosion
- nested look-behind assertions
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/c0a1430287f9e174.
Report an issue: GitHub.