twigphp/Twig · error · RuntimeError
Regexp " " passed to "matches" is not valid
Error message
Regexp "%s" passed to "matches" is not valid
What it means
The Twig `matches` operator/filter runs preg_match on the given PCRE pattern. When preg_match emits a warning (malformed pattern, bad modifiers, etc.), a custom error handler converts it into a RuntimeError quoting the invalid regexp plus PHP's own warning text (the leading 'preg_match(): ' prefix is stripped via substr($m, 12)).
Solutions
- Fix the pattern: wrap it in delimiters (e.g. '/pattern/') and verify it compiles (test with preg_match in PHP or an online PCRE checker).
- Escape or choose delimiters that do not appear in the pattern, or use alternative delimiters like '#...#'.
- If the pattern is dynamic, validate it before use (e.g. @preg_match($pattern, '') === false check) and fall back to a safe pattern.
- Remove unsupported modifiers/constructs for PHP PCRE (compare with the regex source syntax).
Example fix
// before (template)
{% if value matches '^[0-9]+$' %}
// after
{% if value matches '/^[0-9]+$/' %} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate a PCRE pattern before using it in matches
function isValidPcre(string $pattern): bool {
return @\preg_match($pattern, '') !== false;
} Try / catch
try {
$ok = \Twig\Extension\CoreExtension::matches($regexp, $str);
} catch (\Twig\Error\RuntimeError $e) {
// invalid regexp: log and treat as non-match or use a fallback pattern
$ok = 0;
} Prevention
- Always delimit patterns: '/pattern/', '#pattern#'.
- Test dynamic patterns with @preg_match before rendering.
- Escape delimiters inside patterns or pick delimiters not used in the expression.
- Validate user-supplied regex input against a safe subset/length limit.
When it happens
Trigger: {{ email matches '/^[a-z]+$/i' }} with a malformed pattern such as unmatched delimiters ('abc'), unbalanced parentheses ('/(/'), unknown modifiers ('/x/u_z'), or patterns that fail compilation; a truncated pattern built by string interpolation.
Common situations: Building regexes dynamically from user/config input with unescaped delimiters; patterns authored for another flavor (e.g. JavaScript) using unsupported constructs; missing delimiters when copying regexes from other tools; multibyte modifier mistakes.
Related errors
- Regexp " " passed to "matches" failed: .
- Regexp " " passed to "matches" is not valid: .
- Unknown " " configuration.
- The " " modifier takes exactly one argument (0 given).
- The " " modifier takes exactly one argument (2 given).
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/cd0cdd1c667bbcee.
Report an issue: GitHub.
Appendix: source
Thrown at src/Extension/CoreExtension.php:1196
return $a <=> (string) $b;
}
return (float) $aTrim <=> $b;
}
// fallback to <=>
return $a <=> $b;
}
/**
* @throws RuntimeError When the regular expression cannot be evaluated
*
* @internal
*/
public static function matches(string $regexp, ?string $str): int
{
set_error_handler(static function ($t, $m) use ($regexp) {
throw new RuntimeError(\sprintf('Regexp "%s" passed to "matches" is not valid', $regexp).substr($m, 12));
});
try {
if (false === $result = preg_match($regexp, $str ?? '')) {
throw new RuntimeError(\sprintf('Regexp "%s" passed to "matches" failed: %s.', $regexp, preg_last_error_msg()));
}
return $result;
} finally {
restore_error_handler();
}
}
/**
* Returns a trimmed string.
*
* @param string|\Stringable|null $string
* @param string|null $characterMask
* @param string $side left, right, or bothView on GitHub (pinned to a414c3a491)