Resolve Regex Pattern Timeout Issues
Fix regex pattern timeouts caused by catastrophic backtracking, ReDoS vulnerabilities, and inefficient quantifiers. Optimize patterns with safe alternatives.
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
Nested quantifiers cause exponential backtracking
Error: Regular expression timeout after 5000ms
ReDoS: Pattern (a+)+ is vulnerable to catastrophic backtracking
Maximum call stack size exceeded
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 Paste your regex into the Regex Tester to test with sample inputs.
-
2
Look for nested quantifiers:
(x+)+,(x*)*,(x+)*,(x|y)*. -
3
Flatten nested groups: replace
(a+)+witha+. - 4 Use atomic groups or possessive quantifiers if your engine supports them.
// Vulnerable: nested quantifiers const emailRegex = /^([a-zA-Z0-9._-]+)*@([a-zA-Z0-9.-]+)*$/; // Hangs on: 'aaaaaaaaaaaaaaaaaaaaaaaa!'
// Fixed: no nesting, atomic matching
const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
// Completes instantly on any input
Overlapping alternatives with greedy quantifiers
TimeoutError: Regex execution exceeded time limit
Pattern took >10 seconds to evaluate
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 Use the Regex Tester to profile your pattern with progressively longer inputs.
-
2
Check if alternatives share common prefixes (e.g.,
http|https). -
3
Factor out common prefixes:
https?instead ofhttp|https. - 4 Ensure alternatives are mutually exclusive where possible.
// Overlapping alternatives const urlRegex = /(http|https|ftp|ftps):\/\/(www\.|.+\.)*[a-z]+/; // Exponential on long non-matching strings
// Factored alternatives, no overlap
const urlRegex = /(?:https?|ftps?):\/\/(?:www\.)?[a-z0-9.-]+\.[a-z]{2,}/;
// Linear time on any input
Greedy .* followed by specific pattern causes excessive scanning
Warning: Regex engine hit backtracking limit
PCRE error: match limit exceeded
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
Replace greedy
.*with lazy.*?when you want the shortest match. -
2
Use negated character classes instead of
.*where possible. - 3 Test with long inputs (1000+ chars) in the Regex Tester.
- 4 Set a match timeout in your application as a safety net.
// Greedy wildcard scans entire document const tagRegex = /<div class="content">.*<\/div>/; // Extremely slow on large HTML
// 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 usesafe-regexpackage. -
Avoid nested quantifiers entirely - flatten
(a+)+toa+. - 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.