Text Processing 2026-04-24

Resolve Regex Pattern Timeout Issues

Fix regex pattern timeouts caused by catastrophic backtracking, ReDoS vulnerabilities, and inefficient quantifiers. Optimize patterns with safe alternatives.

regex timeout regex pattern timeout catastrophic backtracking regex too slow ReDoS fix regex hangs

Regex pattern timeouts happen when a regular expression takes exponential time to evaluate against certain inputs. This is called catastrophic backtracking, and it can freeze your application or create ReDoS (Regular Expression Denial of Service) vulnerabilities. This guide shows how to identify, fix, and prevent slow regex patterns.

Common errors covered

  1. 1 Nested quantifiers cause exponential backtracking
  2. 2 Overlapping alternatives with greedy quantifiers
  3. 3 Greedy .* followed by specific pattern causes excessive scanning
1

Nested quantifiers cause exponential backtracking

Error message
Error: Regular expression timeout after 5000ms ReDoS: Pattern (a+)+ is vulnerable to catastrophic backtracking Maximum call stack size exceeded
Root cause

Patterns with nested quantifiers like (a+)+, (.*)*, or (a|a)+ create exponential backtracking paths. For an input of length N, the engine may try 2^N combinations before failing.

Step-by-step fix

  1. 1 Paste your regex into the Regex Tester to test with sample inputs.
  2. 2 Look for nested quantifiers: (x+)+, (x*)*, (x+)*, (x|y)*.
  3. 3 Flatten nested groups: replace (a+)+ with a+.
  4. 4 Use atomic groups or possessive quantifiers if your engine supports them.
Wrong
// Vulnerable: nested quantifiers
const emailRegex = /^([a-zA-Z0-9._-]+)*@([a-zA-Z0-9.-]+)*$/;
// Hangs on: 'aaaaaaaaaaaaaaaaaaaaaaaa!'
Correct
// Fixed: no nesting, atomic matching
const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
// Completes instantly on any input

2

Overlapping alternatives with greedy quantifiers

Error message
TimeoutError: Regex execution exceeded time limit Pattern took >10 seconds to evaluate
Root cause

When alternatives in (a|ab) overlap and are followed by quantifiers, the engine tries every possible combination of matches. The more the alternatives overlap, the more paths must be explored.

Step-by-step fix

  1. 1 Use the Regex Tester to profile your pattern with progressively longer inputs.
  2. 2 Check if alternatives share common prefixes (e.g., http|https).
  3. 3 Factor out common prefixes: https? instead of http|https.
  4. 4 Ensure alternatives are mutually exclusive where possible.
Wrong
// Overlapping alternatives
const urlRegex = /(http|https|ftp|ftps):\/\/(www\.|.+\.)*[a-z]+/;
// Exponential on long non-matching strings
Correct
// Factored alternatives, no overlap
const urlRegex = /(?:https?|ftps?):\/\/(?:www\.)?[a-z0-9.-]+\.[a-z]{2,}/;
// Linear time on any input

3

Greedy .* followed by specific pattern causes excessive scanning

Error message
Warning: Regex engine hit backtracking limit PCRE error: match limit exceeded
Root cause

A greedy .* consumes the entire input first, then backtracks character by character to find the next part of the pattern. On long inputs with no match near the end, this means scanning the entire string multiple times.

Step-by-step fix

  1. 1 Replace greedy .* with lazy .*? when you want the shortest match.
  2. 2 Use negated character classes instead of .* where possible.
  3. 3 Test with long inputs (1000+ chars) in the Regex Tester.
  4. 4 Set a match timeout in your application as a safety net.
Wrong
// Greedy wildcard scans entire document
const tagRegex = /<div class="content">.*<\/div>/;
// Extremely slow on large HTML
Correct
// Lazy quantifier or negated class
const tagRegex = /<div class="content">.*?<\/div>/;
// Or even better with negated class:
const tagRegex = /<div class="content">[^<]*<\/div>/;

Prevention Tips

  • Always test regex patterns with adversarial inputs (long strings of repeating characters that almost match).
  • Set a timeout for regex execution: Python has re.timeout (3.11+), Node.js can use safe-regex package.
  • Avoid nested quantifiers entirely - flatten (a+)+ to a+.
  • Use the Regex Tester to profile pattern performance before deploying to production.

Frequently Asked Questions

What is catastrophic backtracking in regex?

When a regex engine cannot find a match, it backtracks to try alternative paths. With nested quantifiers, the number of paths grows exponentially with input length. A 25-character string can cause over 33 million backtracking steps.

How can I check if my regex is vulnerable to ReDoS?

Test it with progressively longer non-matching inputs (e.g., 'aaa...!' with increasing 'a' count). If execution time doubles with each added character, you have exponential backtracking. Our Regex Tester helps you experiment safely.

Are some regex engines immune to catastrophic backtracking?

Yes. RE2 (used by Go and available as a library for other languages) uses a linear-time algorithm that cannot backtrack catastrophically. Rust's regex crate also guarantees linear time. NFA-based engines are safe; backtracking engines (PCRE, JavaScript, Python re) are vulnerable.

Related Error Guides

Related Tools

Still stuck? Try our free tools

All tools run in your browser, no signup required.