{"record":{"id":"49bc27957c6bec5e","repo":"sebastianbergmann/phpunit","slug":"format-description-cannot-be-matched-s","errorCode":null,"errorMessage":"Format description cannot be matched: %s","messagePattern":"Format description cannot be matched: (.+?)","errorType":"exception","errorClass":"FrameworkException","httpStatus":null,"severity":"error","filePath":"src/Framework/Constraint/String/StringMatchesFormatDescription.php","lineNumber":86,"sourceCode":"     * @throws FrameworkException\n     */\n    protected function matches(mixed $other): bool\n    {\n        if (!is_string($other)) {\n            return false;\n        }\n\n        $other = $this->convertNewlines($other);\n\n        $matches = @preg_match(\n            $this->regularExpressionForFormatDescription(\n                $this->convertNewlines($this->formatDescription),\n            ),\n            $other,\n        );\n\n        if ($matches === false) {\n            throw new FrameworkException(\n                sprintf(\n                    'Format description cannot be matched: %s',\n                    preg_last_error_msg(),\n                ),\n            );\n        }\n\n        return $matches > 0;\n    }\n\n    protected function failureDescription(mixed $other): string\n    {\n        return 'string matches format description';\n    }\n\n    protected function failureDescriptionInContext(Operator $operator, mixed $role, mixed $other): string\n    {\n        // @codeCoverageIgnoreStart","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Framework/Constraint/String/StringMatchesFormatDescription.php#L68-L104","documentation":"assertStringMatchesFormat() translates its format description (%s, %d, %a, %A, %e, %f, %x, %c, %r...) into a single anchored PCRE regex ('/^...$/s') and runs preg_match(). If PCRE fails on that generated regex (returns false), PHPUnit throws this exception carrying preg_last_error_msg(). The culprit is almost always the generated pattern over-running pcre.backtrack_limit/pcre.recursion_limit on the actual string, not the format syntax itself.","triggerScenarios":"assertStringMatchesFormat($format, $actual) where the format contains multiple greedy or lazy multiline placeholders (%a, %A, %s chains) applied to a long multi-line string, driving backtracking past pcre.backtrack_limit; or the actual string is invalid UTF-8 relative to an implied unicode context.","commonSituations":"Snapshot-ish tests asserting CLI/artisan command output, API responses or templated emails with '%a ... %a ... %a' between concrete lines; large payloads in CI where the PHP pcre.backtrack_limit default (1M) is exceeded; formats copied from sprintf() templates with dozens of placeholders.","solutions":["Reduce placeholder density: anchor with more literal lines between %a/%A placeholders so the regex has less ambiguity","Split the assertion: assert the stable parts with assertStringContainsString() and only variable tokens with assertStringMatchesFormat()","Raise the limit in phpunit.xml or bootstrap: <ini name=\"pcre.backtrack_limit\" value=\"10000000\"/>","For huge outputs, prefer assertStringEqualsStringIgnoringLineEndings or a normalized diff comparison instead of one giant format regex"],"exampleFix":"// before\n$this->assertStringMatchesFormat(\n    \"Header: %s\\n%A\\nBody: %a\\n%A\\nFooter: %s\",\n    $hugeOutput // PCRE backtrack limit exhausted\n);\n\n// after\n$this->assertStringContainsString('Header: ', $hugeOutput);\n$this->assertStringContainsString('Footer: ', $hugeOutput);\n// or raise the limit:\n// <ini name=\"pcre.backtrack_limit\" value=\"10000000\"/> in phpunit.xml","handlingStrategy":"validation","validationCode":"// Keep formats small: assert stable literals with contains, placeholders only where needed:\nforeach (['Header: ', 'Footer: '] as $literal) {\n    if (!str_contains($actual, $literal)) {\n        $this->fail(\"Missing literal: $literal\");\n    }\n}\n$this->assertStringMatchesFormat(\"Body: %d lines\", $bodyLine);","typeGuard":null,"tryCatchPattern":"use PHPUnit\\Framework\\Exception as FrameworkException;\n\ntry {\n    $this->assertStringMatchesFormat($format, $actual);\n} catch (FrameworkException $e) {\n    if (str_contains($e->getMessage(), 'Format description cannot be matched')) {\n        $this->markTestIncomplete('Format regex hit PCRE limit: ' . $e->getMessage());\n    }\n}","preventionTips":["Anchor %a/%A placeholders with literal lines instead of stacking wildcards","Raise <ini name=\"pcre.backtrack_limit\"/> in phpunit.xml for output-heavy suites","For very large documents prefer string diff assertions over one giant format regex"],"tags":["php","phpunit","assertstringmatchesformat","pcre","backtrack-limit","format-string"],"backgroundTag":"regex-backtrack-limit-exceeded","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}