sebastianbergmann/phpunit · error · PHPUnit\Framework\Exception
Regular expression cannot be matched: %s
Error message
Regular expression cannot be matched: %s
What it means
The RegularExpression constraint (matchesRegularExpression() / assertThat with regularExpression()) runs preg_match() with the @ operator; if preg_match returns false, PCRE itself failed and PHPUnit rethrows the PCRE error message. This is not a mismatch (which returns false) — it is the regex engine erroring out, most often a backtrack or recursion limit exceeded by a catastrophic pattern, or invalid UTF-8 in the subject when the pattern uses the /u modifier.
Source
Thrown at src/Framework/Constraint/String/RegularExpression.php:74
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @throws FrameworkException
*/
protected function matches(mixed $other): bool
{
if (!is_string($other)) {
return false;
}
$matches = @preg_match($this->pattern, $other);
if ($matches === false) {
throw new FrameworkException(
sprintf(
'Regular expression cannot be matched: %s',
preg_last_error_msg(),
),
);
}
return $matches > 0;
}
}
View on GitHub (pinned to f123cdb2a2)
Solutions
- Simplify the pattern: replace nested/lazy catch-alls with anchored, specific subpatterns or use preg_match on smaller slices of the subject
- Raise the PCRE limits for the test run: ini_set('pcre.backtrack_limit', '10000000'); (and pcre.recursion_limit if the error names recursion)
- If the error names UTF-8, fix the subject encoding (mb_convert_encoding to UTF-8) or drop the /u modifier when no unicode properties are needed
- Sanitize data-driven patterns: validate them once with @preg_match($pattern, '') === false && preg_last_error() check before use
Example fix
// before
$this->matchesRegularExpression('/^(.*\n)+TOTAL: \\d+$/', $longReport); // backtrack limit
// after
$this->matchesRegularExpression('/^.*\nTOTAL: \\d+$/s', $longReport);
// or in the test bootstrap:
ini_set('pcre.backtrack_limit', '10000000'); Defensive patterns
Strategy: validation
Validate before calling
// Validate the pattern and raise limits before the assertion:
if (@preg_match($pattern, '') === false) {
$this->markTestSkipped('Invalid regex: ' . preg_last_error_msg());
}
ini_set('pcre.backtrack_limit', '10000000');
$this->matchesRegularExpression($pattern, $subject); Type guard
function isMatchablePattern(string $pattern): bool
{
return @preg_match($pattern, '') !== false;
} Try / catch
use PHPUnit\Framework\Exception as FrameworkException;
try {
$this->matchesRegularExpression($pattern, $subject);
} catch (FrameworkException $e) {
if (str_contains($e->getMessage(), 'Regular expression cannot be matched')) {
ini_set('pcre.backtrack_limit', '10000000'); // then re-run once
}
} Prevention
- Avoid nested quantifiers ((a+)+) and chains of greedy catch-alls in assertion patterns
- Set pcre.backtrack_limit explicitly in phpunit.xml so dev and CI match
- For /u patterns, sanitize subject encoding before matching
When it happens
Trigger: matchesRegularExpression($pattern, $subject) where the pattern causes catastrophic backtracking (nested quantifiers like (a+)+) on long subjects exceeding pcre.backtrack_limit, deep recursion exceeding pcre.recursion_limit, or where $subject contains invalid UTF-8 while the pattern carries the u modifier.
Common situations: Golden-output tests matching long log/console strings with loose patterns like '.*foo.*bar.*'; patterns authored with (.*)* ; subjects read from binary-ish files or external APIs with broken encoding; CI boxes where pcre.backtrack_limit is lower than a developer machine; PCRE vs PCRE2 differences across PHP versions.
Related errors
- Format description cannot be matched: %s
- Invalid expected exception message regular expression given:
- Subscriber "%s" does not implement any known interface - did
- Unknown event type "%s"
- Subscriber "%s" does not implement a known interface
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/8b8538fda4730ef8.
Report an issue: GitHub.