{"record":{"id":"b419eb303fcee5e3","repo":"symfony/routing","slug":"cannot-use-utf-8-route-requirements-without-setting-the-utf8","errorCode":null,"errorMessage":"Cannot use UTF-8 route requirements without setting the \"utf8\" option for variable \"%s\" in pattern \"%s\".","messagePattern":"Cannot use UTF-8 route requirements without setting the \"utf8\" option for variable \"(.+?)\" in pattern \"(.+?)\"\\.","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"RouteCompiler.php","lineNumber":191,"sourceCode":"                $nextSeparator = self::findNextSeparator($followingPattern, $useUtf8);\n                $regexp = \\sprintf(\n                    '[^%s%s]+',\n                    preg_quote($defaultSeparator),\n                    $defaultSeparator !== $nextSeparator && '' !== $nextSeparator ? preg_quote($nextSeparator) : ''\n                );\n                if (('' !== $nextSeparator && !preg_match('#^\\{[\\w\\x80-\\xFF]+\\}#', $followingPattern)) || '' === $followingPattern) {\n                    // When we have a separator, which is disallowed for the variable, we can optimize the regex with a possessive\n                    // quantifier. This prevents useless backtracking of PCRE and improves performance by 20% for matching those patterns.\n                    // Given the above example, there is no point in backtracking into {page} (that forbids the dot) when a dot must follow\n                    // after it. This optimization cannot be applied when the next char is no real separator or when the next variable is\n                    // directly adjacent, e.g. '/{x}{y}'.\n                    $regexp .= '+';\n                }\n            } else {\n                if (!preg_match('//u', $regexp)) {\n                    $useUtf8 = false;\n                } elseif (!$needsUtf8 && preg_match('/[\\x80-\\xFF]|(?<!\\\\\\\\)\\\\\\\\(?:\\\\\\\\\\\\\\\\)*+(?-i:X|[pP][\\{CLMNPSZ]|x\\{[A-Fa-f0-9]{3})/', $regexp)) {\n                    throw new \\LogicException(\\sprintf('Cannot use UTF-8 route requirements without setting the \"utf8\" option for variable \"%s\" in pattern \"%s\".', $varName, $pattern));\n                }\n                if (!$useUtf8 && $needsUtf8) {\n                    throw new \\LogicException(\\sprintf('Cannot mix UTF-8 requirement with non-UTF-8 charset for variable \"%s\" in pattern \"%s\".', $varName, $pattern));\n                }\n                $regexp = self::transformCapturingGroupsToNonCapturings($regexp);\n            }\n\n            if ($important) {\n                $token = ['variable', $isSeparator ? $precedingChar : '', $regexp, $varName, false, true];\n            } else {\n                $token = ['variable', $isSeparator ? $precedingChar : '', $regexp, $varName];\n            }\n\n            $tokens[] = $token;\n            $variables[] = $varName;\n        }\n\n        if ($pos < \\strlen($pattern)) {","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/symfony/routing/blob/83fa223250b50f4f018c011e101c330e65ac63cc/RouteCompiler.php#L173-L209","documentation":"A route variable's requirement regex uses UTF-8 features (high bytes, \\X, unicode \\p{...} classes) while the route's \"utf8\" option is not enabled. The compiled regex would be applied byte-wise and misbehave, so compilePattern throws a LogicException asking you to enable utf8 for that variable's pattern.","triggerScenarios":"Compiling a route like new Route('/{city}', ['utf8' => false], ['city' => '[\\p{L}]+']) or with a requirement containing literal accented characters, without the utf8 option.","commonSituations":"Adding unicode-aware requirements (\\p{L}, \\p{N}, accented character classes) to pre-UTF-8-era route definitions; copying requirements from a UTF-8-enabled project into a Symfony 4/5 project with utf8 unset.","solutions":["Enable the utf8 option: new Route('/{city}', options: ['utf8' => true], requirements: ['city' => '[\\p{L}]+']).","In YAML, set options: { utf8: true } on the route.","Rewrite the requirement to be ASCII-only, e.g. '[a-zA-Z]+' or '[^/]+', if UTF-8 matching is not needed.","Upgrade to Symfony 6+, where UTF-8 mode is always on and the option no longer exists."],"exampleFix":"// before\n$route = new Route('/{city}', [], ['city' => '[\\p{L}]+']);\n\n// after\n$route = new Route('/{city}', options: ['utf8' => true], requirements: ['city' => '[\\p{L}]+']);","handlingStrategy":"validation","validationCode":"foreach ($route->getRequirements() as $name => $req) {\n    if (preg_match('/[\\x80-\\xFF]|\\\\\\\\(?:\\\\\\\\)*+(?-i:X|[pP][\\{CLMNPSZ]|x\\{[A-Fa-f0-9]{3})/', $req)\n        && !$route->getOption('utf8')) {\n        $route->setOption('utf8', true); // or reject\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    (new RouteCompiler())->compile($route);\n} catch (\\LogicException $e) {\n    // enable utf8 or make requirements ASCII-only, then retry\n}","preventionTips":["Whenever you use \\p{...} or literal non-ASCII in requirements, set utf8: true.","Prefer ASCII-only requirements ([a-zA-Z0-9-]+) in reusable bundles.","Test-compile all routes in CI to catch option/requirement mismatches."],"tags":["routing","symfony","utf8","regex-requirements"],"backgroundTag":"conflicting-config-options","analyzedSha":"83fa223250b50f4f018c011e101c330e65ac63cc","analyzedAt":"2026-09-14T03:19:46.280Z","contentChangedAt":"2026-09-14T03:19:46.280Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}