symfony/routing · error · LogicException

Cannot use UTF-8 route requirements without setting the…

Error message

Cannot use UTF-8 route requirements without setting the "utf8" option for variable "%s" in pattern "%s".

What it means

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.

Solutions

  1. Enable the utf8 option: new Route('/{city}', options: ['utf8' => true], requirements: ['city' => '[\p{L}]+']).
  2. In YAML, set options: { utf8: true } on the route.
  3. Rewrite the requirement to be ASCII-only, e.g. '[a-zA-Z]+' or '[^/]+', if UTF-8 matching is not needed.
  4. Upgrade to Symfony 6+, where UTF-8 mode is always on and the option no longer exists.

Example fix

// before
$route = new Route('/{city}', [], ['city' => '[\p{L}]+']);

// after
$route = new Route('/{city}', options: ['utf8' => true], requirements: ['city' => '[\p{L}]+']);
Defensive patterns

Strategy: validation

Validate before calling

foreach ($route->getRequirements() as $name => $req) {
    if (preg_match('/[\x80-\xFF]|\\\\(?:\\\\)*+(?-i:X|[pP][\{CLMNPSZ]|x\{[A-Fa-f0-9]{3})/', $req)
        && !$route->getOption('utf8')) {
        $route->setOption('utf8', true); // or reject
    }
}

Try / catch

try {
    (new RouteCompiler())->compile($route);
} catch (\LogicException $e) {
    // enable utf8 or make requirements ASCII-only, then retry
}

Prevention

When it happens

Trigger: Compiling a route like new Route('/{city}', ['utf8' => false], ['city' => '[\p{L}]+']) or with a requirement containing literal accented characters, without the utf8 option.

Common situations: 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.

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


AI-assisted analysis of symfony/routing@83fa223250 (2026-09-14). Data as JSON: /api/errors/b419eb303fcee5e3. Report an issue: GitHub.

Appendix: source

Thrown at RouteCompiler.php:191

                $nextSeparator = self::findNextSeparator($followingPattern, $useUtf8);
                $regexp = \sprintf(
                    '[^%s%s]+',
                    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)) {

View on GitHub (pinned to 83fa223250)