symfony/routing · error · LogicException
Cannot mix UTF-8 requirement with non-UTF-8 charset for…
Error message
Cannot mix UTF-8 requirement with non-UTF-8 charset for variable "%s" in pattern "%s".
What it means
Opposite of error 77: the route's "utf8" option is enabled, but a variable's requirement regex is not valid UTF-8 (preg_match('//u', $regexp) fails), so matching semantics would be inconsistent. compilePattern throws a LogicException naming the variable and pattern.
Solutions
- Fix the requirement string so it is valid UTF-8 (mb_check_encoding($regexp, 'UTF-8')).
- Re-save the config file with UTF-8 encoding.
- Simplify the requirement to an ASCII-safe pattern like [a-z0-9-]+ if unicode matching is unnecessary.
- Sanitize programmatically: mb_convert_encoding($requirement, 'UTF-8', 'ISO-8859-1').
Example fix
// before (requirement bytes are not valid UTF-8)
$route = new Route('/{slug}', options: ['utf8' => true], requirements: ["slug" => "caf\xE9"]);
// after
$route = new Route('/{slug}', options: ['utf8' => true], requirements: ['slug' => 'café|[a-z-]+']); Defensive patterns
Strategy: validation
Validate before calling
if ($route->getOption('utf8')) {
foreach ($route->getRequirements() as $name => $req) {
if (!mb_check_encoding($req, 'UTF-8')) {
throw new \RuntimeException("Requirement for '$name' is not valid UTF-8.");
}
}
} Try / catch
try {
(new RouteCompiler())->compile($route);
} catch (\LogicException $e) {
// fix requirement encoding or drop the utf8 option, then retry
} Prevention
- Keep requirement strings as ASCII regexes whenever possible.
- Check config file encodings; ensure YAML is parsed as UTF-8.
- Never interpolate raw external bytes into requirement regexes; sanitize first.
When it happens
Trigger: Compiling a route with options ['utf8' => true] and a requirement containing invalid/non-UTF-8 bytes, e.g. ['slug' => "caf\xE9|"] or a Latin-1 encoded requirement from a config file.
Common situations: Requirements loaded from mis-encoded YAML/PHP config files; concatenating encoded user input into requirement strings; enabling utf8 on all routes globally while some legacy requirements are ASCII-escaped bytes.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Cannot mix UTF-8 requirements with non-UTF-8 pattern
- Cannot use UTF-8 route requirements without setting the…
- Cannot use UTF-8 route patterns without setting the "utf8"…
- Parameter " " for route " " must match " " (" " given) to…
- Parameters for route
AI-assisted analysis of symfony/routing@83fa223250 (2026-09-14).
Data as JSON: /api/errors/c5321fec3a19a132.
Report an issue: GitHub.
Appendix: source
Thrown at RouteCompiler.php:194
preg_quote($defaultSeparator),
$defaultSeparator !== $nextSeparator && '' !== $nextSeparator ? preg_quote($nextSeparator) : ''
);
if (('' !== $nextSeparator && !preg_match('#^\{[\w\x80-\xFF]+\}#', $followingPattern)) || '' === $followingPattern) {
// When we have a separator, which is disallowed for the variable, we can optimize the regex with a possessive
// quantifier. This prevents useless backtracking of PCRE and improves performance by 20% for matching those patterns.
// Given the above example, there is no point in backtracking into {page} (that forbids the dot) when a dot must follow
// after it. This optimization cannot be applied when the next char is no real separator or when the next variable is
// directly adjacent, e.g. '/{x}{y}'.
$regexp .= '+';
}
} else {
if (!preg_match('//u', $regexp)) {
$useUtf8 = false;
} elseif (!$needsUtf8 && preg_match('/[\x80-\xFF]|(?<!\\\\)\\\\(?:\\\\\\\\)*+(?-i:X|[pP][\{CLMNPSZ]|x\{[A-Fa-f0-9]{3})/', $regexp)) {
throw new \LogicException(\sprintf('Cannot use UTF-8 route requirements without setting the "utf8" option for variable "%s" in pattern "%s".', $varName, $pattern));
}
if (!$useUtf8 && $needsUtf8) {
throw new \LogicException(\sprintf('Cannot mix UTF-8 requirement with non-UTF-8 charset for variable "%s" in pattern "%s".', $varName, $pattern));
}
$regexp = self::transformCapturingGroupsToNonCapturings($regexp);
}
if ($important) {
$token = ['variable', $isSeparator ? $precedingChar : '', $regexp, $varName, false, true];
} else {
$token = ['variable', $isSeparator ? $precedingChar : '', $regexp, $varName];
}
$tokens[] = $token;
$variables[] = $varName;
}
if ($pos < \strlen($pattern)) {
$tokens[] = ['text', substr($pattern, $pos)];
}
View on GitHub (pinned to 83fa223250)