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

  1. Reduce the number of quantified sub-expressions below 32768 by factoring repeated parts into loops or character classes.
  2. Split the pattern into several smaller regexes and combine matches in code.
  3. 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

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


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/c0a1430287f9e174. Report an issue: GitHub.