jhy/jsoup · error · ValidationException

Pattern complexity error

Error message

Pattern complexity error

What it means

When compiling a pattern causes OutOfMemoryError or StackOverflowError (RE2 compiles may exhaust VM resources on huge bounded repetitions like (x){0,1000000} or deeply nested groups), compile throws ValidationException with the constant PatternComplexityError. It distinguishes resource exhaustion from plain syntax errors.

Solutions

  1. Reduce repetition bounds and nesting in the pattern; simplify or split it
  2. Cap user-supplied pattern length and repetition counts before compiling
  3. Catch ValidationException and reject overly complex patterns with a friendlier message
  4. Pre-validate structure (e.g. limit max {m,n} values) with a lint pass

Example fix

// before
Regex r = Re2jRegex.compile("(a|b|c){0,200000}");
// after
Regex r = Re2jRegex.compile("(a|b|c){0,100}"); // bounded complexity
Defensive patterns

Strategy: validation

Validate before calling

if (pattern.length() > 500 || java.util.regex.Pattern.compile("\\\\{\\s*\\d{4,}").matcher(pattern).find()) throw new IllegalArgumentException("Pattern too complex");

Type guard

boolean isBoundedPattern(String p) { return p.length() <= 500 && !p.matches(".*\\{\\d{4,}.*"); }

Try / catch

try { Regex r = Re2jRegex.compile(pattern); } catch (ValidationException e) { if (e.getMessage().contains("complexity")) { /* reject as too complex */ } }

Prevention

When it happens

Trigger: Compiling regexes with extremely large counted repetitions (e.g. a{0,100000}), very deep nesting, or enormous alternation sets that blow up RE2's compile-time automaton construction.

Common situations: User-supplied regex limits that compile into huge NFAs; generated patterns embedding big counts; security-sensitive endpoints accepting arbitrary regexes (ReDoS-hardening paths) where input size is unchecked.

Related errors


AI-assisted analysis of jhy/jsoup@9851ac5d9c (2026-09-08). Data as JSON: /api/errors/9ff2f7a9f5827ece. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/org/jsoup/helper/Re2jRegex.java:23

 */
final class Re2jRegex extends Regex {
    private static final java.util.regex.Pattern unused = java.util.regex.Pattern.compile("");
    private static final String PatternComplexityError = "Pattern complexity error";

    private final com.google.re2j.Pattern re2jPattern;

    private Re2jRegex(com.google.re2j.Pattern re2jPattern) {
        super(unused);
        this.re2jPattern = re2jPattern;
    }

    public static Regex compile(String regex) {
        try {
            return new Re2jRegex(com.google.re2j.Pattern.compile(regex));
        } catch (RuntimeException e) {
            throw new ValidationException("Pattern syntax error: " + e.getMessage());
        } catch (OutOfMemoryError | StackOverflowError e) { // complex patterns may exhaust VM resources
            throw new ValidationException(PatternComplexityError);
        }
    }

    @Override
    public Matcher matcher(CharSequence input) {
        return new Re2jMatcher(re2jPattern.matcher(input));
    }

    @Override
    public String toString() {
        return re2jPattern.toString();
    }

    private static final class Re2jMatcher implements Matcher {
        private final com.google.re2j.Matcher delegate;

        Re2jMatcher(com.google.re2j.Matcher delegate) {
            this.delegate = delegate;

View on GitHub (pinned to 9851ac5d9c)