{"record":{"id":"9901580152000891","repo":"twigphp/Twig","slug":"regexp-s-passed-to-matches-is-not-valid-s","errorCode":null,"errorMessage":"Regexp \"%s\" passed to \"matches\" is not valid: %s.","messagePattern":"Regexp \"(.+?)\" passed to \"matches\" is not valid: (.+?)\\.","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"src/Node/Expression/Binary/MatchesBinary.php","lineNumber":35,"sourceCode":"use Twig\\Node\\Expression\\AbstractExpression;\nuse Twig\\Node\\Expression\\ConstantExpression;\nuse Twig\\Node\\Expression\\ReturnBoolInterface;\nuse Twig\\Node\\Node;\n\nclass MatchesBinary extends AbstractBinary implements ReturnBoolInterface, CoercesChildrenToStringInterface\n{\n    public function __construct(Node $left, Node $right, int $lineno)\n    {\n        if (!$left instanceof AbstractExpression) {\n            trigger_deprecation('twig/twig', '3.24', 'Passing a \"%s\" instance to \"%s()\" first argument is deprecated, pass an \"AbstractExpression\" instance instead.', $left::class, __METHOD__);\n        }\n        if (!$right instanceof AbstractExpression) {\n            trigger_deprecation('twig/twig', '3.24', 'Passing a \"%s\" instance to \"%s()\" second argument is deprecated, pass an \"AbstractExpression\" instance instead.', $right::class, __METHOD__);\n        }\n\n        if ($right instanceof ConstantExpression) {\n            $regexp = $right->getAttribute('value');\n            set_error_handler(static fn ($t, $m) => throw new SyntaxError(\\sprintf('Regexp \"%s\" passed to \"matches\" is not valid: %s.', $regexp, substr($m, 14)), $lineno));\n            try {\n                preg_match($regexp, '');\n            } finally {\n                restore_error_handler();\n            }\n        }\n\n        parent::__construct($left, $right, $lineno);\n    }\n\n    public function compile(Compiler $compiler): void\n    {\n        $compiler\n            ->raw('CoreExtension::matches(')\n            ->subcompile($this->getNode('right'))\n            ->raw(', ')\n            ->subcompile($this->getNode('left'))\n            ->raw(')')","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/Node/Expression/Binary/MatchesBinary.php#L17-L53","documentation":"The `matches` operator in Twig applies a PCRE regexp via preg_match. When the right-hand operand is a constant string, the node constructor eagerly validates it during compilation; if preg_match emits a warning (bad delimiter, unknown modifier, etc.) the error handler converts it into this SyntaxError so the failure surfaces at compile time with the template line.","triggerScenarios":"Compiling a template like `{{ name matches '/foo/' }}` where the constant regex is malformed: missing delimiters, `'/foo/g'` (unknown modifier g), unbalanced parentheses, or invalid escape sequences. Also constructing MatchesBinary with a ConstantExpression holding an invalid regexp in PHP.","commonSituations":"Copy-pasting regexes from JavaScript (with `/g` or `/i` misplacement), forgetting delimiters (`'foo+'` instead of `'/foo+/'`), or quoting mistakes in template strings that break the pattern.","solutions":["Fix the constant regexp in the template: wrap it in valid delimiters (e.g. `/pattern/`) and remove unsupported flags like `g`.","Test the pattern with preg_match in plain PHP or a regex tool to confirm it compiles under PCRE.","If the regexp is dynamic, pass it as a variable expression instead of a constant (validation then happens at runtime)."],"exampleFix":"// before (template)\n{% if email matches '\\\\S+@\\\\S+' %}\n// after\n{% if email matches '/\\\\S+@\\\\S+/' %}","handlingStrategy":"validation","validationCode":"function isValidTwigRegex(string $pattern): bool {\n    set_error_handler(static fn () => false);\n    try { preg_match($pattern, ''); return preg_last_error() === PREG_NO_ERROR; }\n    finally { restore_error_handler(); }\n}\nif (!isValidTwigRegex('/^\\\\S+@\\\\S+$/')) { /* fix pattern before embedding in template */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always delimit regexes in Twig (`/pattern/`), never pass bare patterns.","Strip JavaScript-only flags (g, y) before moving a regex into a Twig template.","Test patterns with preg_match in PHP during development to catch PCRE incompatibilities early."],"tags":["twig","regex","pcre","template-compilation"],"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"}