{"record":{"id":"8b8538fda4730ef8","repo":"sebastianbergmann/phpunit","slug":"regular-expression-cannot-be-matched-s","errorCode":null,"errorMessage":"Regular expression cannot be matched: %s","messagePattern":"Regular expression cannot be matched: (.+?)","errorType":"exception","errorClass":"PHPUnit\\Framework\\Exception","httpStatus":null,"severity":"error","filePath":"src/Framework/Constraint/String/RegularExpression.php","lineNumber":74,"sourceCode":"        );\n    }\n\n    /**\n     * Evaluates the constraint for parameter $other. Returns true if the\n     * constraint is met, false otherwise.\n     *\n     * @throws FrameworkException\n     */\n    protected function matches(mixed $other): bool\n    {\n        if (!is_string($other)) {\n            return false;\n        }\n\n        $matches = @preg_match($this->pattern, $other);\n\n        if ($matches === false) {\n            throw new FrameworkException(\n                sprintf(\n                    'Regular expression cannot be matched: %s',\n                    preg_last_error_msg(),\n                ),\n            );\n        }\n\n        return $matches > 0;\n    }\n}\n","sourceCodeStart":56,"sourceCodeEnd":85,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Framework/Constraint/String/RegularExpression.php#L56-L85","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n$this->matchesRegularExpression('/^(.*\\n)+TOTAL: \\\\d+$/', $longReport); // backtrack limit\n\n// after\n$this->matchesRegularExpression('/^.*\\nTOTAL: \\\\d+$/s', $longReport);\n// or in the test bootstrap:\nini_set('pcre.backtrack_limit', '10000000');","handlingStrategy":"validation","validationCode":"// Validate the pattern and raise limits before the assertion:\nif (@preg_match($pattern, '') === false) {\n    $this->markTestSkipped('Invalid regex: ' . preg_last_error_msg());\n}\nini_set('pcre.backtrack_limit', '10000000');\n\n$this->matchesRegularExpression($pattern, $subject);","typeGuard":"function isMatchablePattern(string $pattern): bool\n{\n    return @preg_match($pattern, '') !== false;\n}","tryCatchPattern":"use PHPUnit\\Framework\\Exception as FrameworkException;\n\ntry {\n    $this->matchesRegularExpression($pattern, $subject);\n} catch (FrameworkException $e) {\n    if (str_contains($e->getMessage(), 'Regular expression cannot be matched')) {\n        ini_set('pcre.backtrack_limit', '10000000'); // then re-run once\n    }\n}","preventionTips":["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"],"tags":["php","phpunit","regex","pcre","backtrack-limit","assertmatchesregexp"],"backgroundTag":"regex-backtrack-limit-exceeded","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}