oracle/graal · error · UnsupportedRegexException
Bounded quantifier tracking would consume too much memory at
Error message
Bounded quantifier tracking would consume too much memory at match time: up to %d bytes. Limit: %d bytes
What it means
Thrown while choosing a CounterTracker implementation: for bounded-quantifier counters with upperBound above 64*MAX_BITSET_SIZE, the engine falls back to CounterTrackerList, whose match-time memory is numberOfCells * upperBound * 4 bytes. If that exceeds TRegexMaxCounterTrackerMemoryConsumptionInForceLinearExecutionMode (100 KB), compilation is rejected because the linear executor would allocate too much per match.
Source
Thrown at regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/dfa/CounterTracker.java:112
int upperBound = Math.max(min, max);
CounterTracker tracker;
int numberOfCells = trackerSizes[i];
if (regressionTestMode) {
tracker = new RegressionModeCounterTracker(min, max, numberOfCells, trivialAlwaysReEnter.get(i), trivialNeverReEnter.get(i), dataBuilder);
} else if (trivialAlwaysReEnter.get(i)) {
tracker = new CounterTrackerTrivialAlwaysReEnter(min, numberOfCells, dataBuilder);
} else if (trivialNeverReEnter.get(i)) {
tracker = new CounterTrackerTrivialNeverReEnter(min, max, numberOfCells, dataBuilder);
} else if (upperBound <= 64) {
tracker = new CounterTrackerLong(min, max, numberOfCells, dataBuilder);
} else if (upperBound <= 128) {
tracker = new CounterTrackerLong2(min, max, numberOfCells, dataBuilder);
} else if (upperBound <= 64 * CounterTrackerBitSetWithOffset.MAX_BITSET_SIZE) {
tracker = new CounterTrackerBitSetWithOffset(min, max, numberOfCells, dataBuilder);
} else {
long maxMemoryConsumption = (long) numberOfCells * (long) upperBound * 4;
if (maxMemoryConsumption > TRegexOptions.TRegexMaxCounterTrackerMemoryConsumptionInForceLinearExecutionMode) {
throw new UnsupportedRegexException(String.format("Bounded quantifier tracking would consume too much memory at match time: up to %d bytes. Limit: %d bytes", maxMemoryConsumption,
TRegexOptions.TRegexMaxCounterTrackerMemoryConsumptionInForceLinearExecutionMode));
}
tracker = new CounterTrackerList(min, max, numberOfCells, dataBuilder);
}
result[i] = tracker;
}
return result;
}
/**
* Returns true whenever the current state of the counter satisfies the given constraint. The
* two data array arguments are the mutable data in which the counters are stored. Note that
* this assumes that the constraints concerns the counter tracked by this tracker.
*/
public boolean canExecute(long constraint, long[] fixedData, int[][] intArrays) {
int kind = TransitionConstraint.getKind(constraint);
int sId = TransitionConstraint.getStateID(constraint);
CompilerAsserts.partialEvaluationConstant(constraint);View on GitHub (pinned to a66e9ccd1d)
Solutions
- Lower the quantifier upper bounds (e.g. replace x{0,100000} with x* plus a length check in code).
- Reduce the number of simultaneously active bounded quantifiers.
- Do not force linear execution mode — let the engine use the backtracking executor, which needs no counter tracker memory.
- Validate the counted bound at runtime instead of in the pattern.
Example fix
// before
String pattern = "(a{0,100000}b){5}";
// after
String pattern = "(a*b){5}"; // then check total length or count in application code Defensive patterns
Strategy: validation
Validate before calling
Matcher m = Pattern.compile("\\{(\\d+),(\\d+)\\}").matcher(pattern);
while (m.find()) { int max = Integer.parseInt(m.group(2)); if (max > 10_000) throw new IllegalArgumentException("quantifier upper bound too high for linear execution (memory cap 100KB)"); } Type guard
null
Try / catch
try { compile(pattern); } catch (UnsupportedRegexException e) { if (e.getMessage().contains("too much memory")) { /* lower bounds or use backtracking engine */ } } Prevention
- Avoid very large explicit quantifier upper bounds; use * + a length check.
- Do not force linear execution mode on quantifier-heavy patterns.
- Keep the number of simultaneous bounded quantifiers small.
When it happens
Trigger: Compiling in linear-execution mode a regex with a bounded quantifier whose upper bound is very large (thousands+) combined with enough concurrent counter cells, e.g. (a{0,100000}b){5}, so cells * max * 4 > 102400 bytes.
Common situations: Patterns with huge counted bounds like x{1,1000000}; forcing linear execution options (no backtracking fallback) on quantifier-heavy patterns; ported .NET/ICU patterns with very high explicit bounds.
Related errors
- too many quantifiers
- Regex with overlapping bounded quantifier (after look-ahead
- Cannot compile regex with empty state to DFA/NFA
- empty path with look-ahead assertion in expression with boun
- PureNFA explosion
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/cb3927253228d2e9.
Report an issue: GitHub.