{"record":{"id":"a3c88410d54751fa","repo":"twigphp/Twig","slug":"regexp-s-passed-to-matches-failed-s","errorCode":null,"errorMessage":"Regexp \"%s\" passed to \"matches\" failed: %s.","messagePattern":"Regexp \"(.+?)\" passed to \"matches\" failed: (.+?)\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/Extension/CoreExtension.php","lineNumber":1200,"sourceCode":"        }\n\n        // fallback to <=>\n        return $a <=> $b;\n    }\n\n    /**\n     * @throws RuntimeError When the regular expression cannot be evaluated\n     *\n     * @internal\n     */\n    public static function matches(string $regexp, ?string $str): int\n    {\n        set_error_handler(static function ($t, $m) use ($regexp) {\n            throw new RuntimeError(\\sprintf('Regexp \"%s\" passed to \"matches\" is not valid', $regexp).substr($m, 12));\n        });\n        try {\n            if (false === $result = preg_match($regexp, $str ?? '')) {\n                throw new RuntimeError(\\sprintf('Regexp \"%s\" passed to \"matches\" failed: %s.', $regexp, preg_last_error_msg()));\n            }\n\n            return $result;\n        } finally {\n            restore_error_handler();\n        }\n    }\n\n    /**\n     * Returns a trimmed string.\n     *\n     * @param string|\\Stringable|null $string\n     * @param string|null             $characterMask\n     * @param string                  $side          left, right, or both\n     *\n     * @throws RuntimeError When an invalid trimming side is used\n     *\n     * @internal","sourceCodeStart":1182,"sourceCodeEnd":1218,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/Extension/CoreExtension.php#L1182-L1218","documentation":"This error comes from Twig's `matches` operator implementation (CoreExtension::matches). Twig first validates the regular expression via preg_match with a temporary error handler; if preg_match itself returns false (PCRE executed but failed), Twig throws this RuntimeError with preg_last_error_msg() describing the PCRE failure. It indicates the pattern was syntactically accepted but the match operation failed at the PCRE engine level (e.g. backtracking limit exceeded).","triggerScenarios":"Calling Twig's `matches` operator (twig_matches -> CoreExtension::matches) when preg_match($regexp, $str ?? '') returns false: typically PREG_BACKTRACK_LIMIT_ERROR (catastrophic backtracking on a complex pattern/large subject) or PREG_RECURSION_LIMIT_ERROR. Note that syntactically invalid patterns raise the separate 'is not valid' error via the custom error handler, not this one.","commonSituations":"Templates running user-supplied regexes against large strings; regexes with nested quantifiers like (a+)+ causing backtrack limit exhaustion on shared hosting with low pcre.backtrack_limit; patterns that are valid but too complex for the subject size.","solutions":["Simplify the regex to avoid catastrophic backtracking (replace nested quantifiers, use atomic groups or possessive quantifiers)","Increase pcre.backtrack_limit in php.ini or via ini_set before rendering (e.g. ini_set('pcre.backtrack_limit', '10000000'))","Pre-validate the pattern and subject sizes before running `matches`, splitting large subjects into chunks","Log preg_last_error() alongside the message to identify the exact PCRE error code"],"exampleFix":"// before\n{% if description matches '/^(a+)+$/' %}...{% endif %}\n// after (in a PHP extension/twig environment)\nini_set('pcre.backtrack_limit', '10000000');\n// or simplify the pattern\n{% if description matches '/^a+$/' %}...{% endif %}","handlingStrategy":"try-catch","validationCode":"if (@preg_match($regexp, '') === false || preg_last_error() !== PREG_NO_ERROR) {\n    throw new \\InvalidArgumentException('Unsafe or pathological regex');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $ok = preg_match($regexp, $subject);\n    if ($ok === false) {\n        throw new \\RuntimeException(preg_last_error_msg());\n    }\n} catch (\\Throwable $e) {\n    ini_set('pcre.backtrack_limit', '10000000');\n    // retry with simplified pattern or fail gracefully in template\n}","preventionTips":["Avoid nested quantifiers and pathological patterns in template regexes","Keep pcre.backtrack_limit generously configured for large subjects","Test templates with representative large inputs","Prefer literal string comparisons or startswith/endswith tests over complex regexes when possible"],"tags":["regex","twig","pcre","runtime-error"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"a414c3a491defb5a60f2fc88ef79ff37c90010cd","analyzedAt":"2026-09-13T15:10:46.849Z","contentChangedAt":"2026-09-13T15:10:46.849Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}