sebastianbergmann/phpunit · error · PHPUnit\Framework\Exception
Invalid expected exception message regular expression given:
Error message
Invalid expected exception message regular expression given: %s
What it means
The ExceptionMessageMatchesRegularExpression constraint backs expectExceptionMessageMatches(): it runs @preg_match($this->regularExpression, $message). When PCRE rejects the pattern (preg_match returns false rather than 0 or 1), it throws Framework\Exception('Invalid expected exception message regular expression given: <pattern>'). The failure is in the pattern itself, not in the tested code.
Source
Thrown at src/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpression.php:53
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @throws \PHPUnit\Framework\Exception
* @throws Exception
*/
protected function matches(mixed $other): bool
{
if (!is_string($other)) {
return false;
}
$match = @preg_match($this->regularExpression, $other);
if ($match === false) {
throw new \PHPUnit\Framework\Exception(
sprintf(
'Invalid expected exception message regular expression given: %s',
$this->regularExpression,
),
);
}
return $match === 1;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*/
protected function failureDescription(mixed $other): string
{View on GitHub (pinned to f123cdb2a2)
Solutions
- Make the pattern a valid PCRE expression with matching delimiters, e.g. '/timeout after \d+ seconds/i'
- If you only need a literal check, use expectExceptionMessage($substring) instead — no regex involved
- Test dynamic patterns before use: if (@preg_match($pattern, '') === false) { /* fix pattern */ }
- Simplify the regex; a long anchored pattern is more likely to contain a syntax slip than a short one
Example fix
// before
$this->expectException(TimeoutException::class);
$this->expectExceptionMessageMatches('timeout after \d+ seconds'); // no delimiters
// after
$this->expectException(TimeoutException::class);
$this->expectExceptionMessageMatches('/timeout after \d+ seconds/i'); Defensive patterns
Strategy: validation
Validate before calling
$pattern = '/timeout after \d+ seconds/i';
if (@preg_match($pattern, '') === false) {
throw new InvalidArgumentException("Invalid regex: {$pattern}");
} Type guard
static function isValidPcrePattern(string $pattern): bool
{
return @preg_match($pattern, '') !== false;
} Try / catch
try {
$this->expectExceptionMessageMatches($pattern);
} catch (\PHPUnit\Framework\Exception $e) {
if (str_contains($e->getMessage(), 'Invalid expected exception message regular expression')) {
// fix the pattern (delimiters/modifiers) before re-running
}
throw $e;
} Prevention
- Always include delimiters and keep modifiers to the well-known set (i u i? m s x) — exactly one leading delimiter pair
- Prefer expectExceptionMessage($substring) for literal checks; reserve regex for real patterns
- Add a lint step for test helpers that build regexes from variables
When it happens
Trigger: Calling $this->expectExceptionMessageMatches($pattern) with a malformed PCRE pattern: missing delimiters ('SomeMessage' with no /.../), unbalanced delimiters, an unknown trailing modifier, or invalid UTF-8 sequences with the u modifier.
Common situations: Upgrading from PHPUnit 9's expectExceptionMessageRegExp where delimiter habits differed; copy-pasting substrings instead of full patterns; patterns assembled dynamically where a fragment is empty or malformed.
Related errors
- Regular expression cannot be matched: %s
- Expected deprecation with message matching regular expressio
- Class or interface "%s" does not exist
- Format description cannot be matched: %s
- Expected deprecation with message "%s" was not triggered
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/b4e6aa2629298b3d.
Report an issue: GitHub.