oracle/graal · error · UnsupportedRegexException

case-unfolding of case-insensitive string is too complex

Error message

case-unfolding of case-insensitive string is too complex

What it means

Thrown by MultiCharacterCaseFolding.unfoldSegment when the recursion depth of case-unfolding a case-insensitive string segment exceeds 12. To match case-insensitively against all foldings (e.g. 'ss' vs U+00DF, Greek sigma variants, ligatures), the parser enumerates reverse unfoldings with backtracking; segments whose alternatives multiply beyond depth 12 are rejected as too complex.

Source

Thrown at regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/MultiCharacterCaseFolding.java:171

    private static List<Integer> caseFold(CaseFoldData.CaseFoldAlgorithm algorithm, int[] codepoints) {
        List<Integer> caseFolded = new ArrayList<>();
        for (int codepoint : codepoints) {
            int[] folded = caseFold(algorithm, codepoint);
            if (folded == null) {
                caseFolded.add(codepoint);
            } else {
                for (int foldedElem : folded) {
                    caseFolded.add(foldedElem);
                }
            }
        }
        return caseFolded;
    }

    private static void unfoldSegment(CaseFoldData.CaseFoldAlgorithm algorithm, RegexASTBuilder astBuilder, ArrayList<OracleDBCharClassTrieNode> leafNodes, List<Integer> caseFolded,
                    List<Unfolding> unfoldings, int start, int end, int backtrackingDepth, boolean dropAsciiOnStart, boolean transitiveEquivalence, CompilationBuffer compilationBuffer) {
        if (backtrackingDepth > 12) {
            throw new UnsupportedRegexException("case-unfolding of case-insensitive string is too complex");
        }
        // The terminating condition of this recursion. This is reached when we have generated
        // an alternative that covers the entire case-folded segment given by `start` and `end`.
        if (start == end) {
            return;
        }
        // This shouldn't happen in our current use case, but it's included for completeness.
        if (unfoldings.isEmpty()) {
            addString(astBuilder, leafNodes, caseFolded.subList(start, end), compilationBuffer);
            return;
        }
        Unfolding unfolding = unfoldings.get(0);
        // Fast-forward to the next possible unfolding.
        if (unfolding.getStart() > start) {
            addString(astBuilder, leafNodes, caseFolded.subList(start, unfolding.getStart()), compilationBuffer);
            unfoldSegment(algorithm, astBuilder, leafNodes, caseFolded, unfoldings, unfolding.getStart(), end, backtrackingDepth, dropAsciiOnStart, transitiveEquivalence, compilationBuffer);
            return;
        }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Shorten the literal run of fold-ambiguous characters, or split it so each segment has fewer consecutive folding alternatives.
  2. Restrict case-insensitivity to the ASCII part, or drop CASE_INSENSITIVE for that segment and normalize input case in application code instead.
  3. Match case-sensitively against pre-lowercased input (and pre-lowercased pattern) when full Unicode folding is not required.

Example fix

// before
Pattern p = Pattern.compile("\u00dfss\u00dfss\u00dfss", Pattern.CASE_INSENSITIVE); // deep unfolding

// after
Pattern p = Pattern.compile(Pattern.quote(input.toLowerCase()), Pattern.CASE_INSENSITIVE); // or match case-sensitively on normalized text
Defensive patterns

Strategy: validation

Validate before calling

// count fold-ambiguous characters in case-insensitive literals before compiling
String foldProne = "s\u00df\u03c3\u03c2i\u0130k\u00f6"; long n = literal.chars().filter(c -> foldProne.indexOf(c) >= 0).count(); if (n > 12) throw new IllegalArgumentException("case-unfolding too complex");

Type guard

null

Try / catch

try { compileCaseInsensitive(pattern); } catch (UnsupportedRegexException e) { /* match case-sensitively on pre-normalized text instead */ }

Prevention

When it happens

Trigger: Compiling a case-insensitive literal string (or string-containing character class, e.g. via \q{...} or set strings) that contains characters with many case-folding equivalences in close succession, e.g. long runs of 's', 'i', 'k', 'sigma' or ligature characters under CASE_INSENSITIVE (especially with Unicode case folding).

Common situations: Case-insensitive matching of German/Greek/Turkish text or ligature-rich input; flavor-specific string sets (OracleDB char-class tries) with case-insensitive flags; patterns generated from user text with many fold-prone letters in a row.

Related errors


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