symfony/routing · error · LogicException
Route pattern " " cannot reference variable name " " more…
Error message
Route pattern "%s" cannot reference variable name "%s" more than once.
What it means
A route pattern may reference the same variable name only once; duplicates would produce an ambiguous PCRE named subpattern and the parameter value would be unclear. compilePattern keeps an accumulating $variables list (host variables first, then path variables) and throws a LogicException when a variable appears again.
Solutions
- Rename one of the duplicated placeholders, e.g. /blog/{slug}/edit/{id}.
- Remove the redundant placeholder if both segments carry the same data.
- If host and path share a value, keep it in one place and use requirements/defaults for the other.
Example fix
// before
$route = new Route('/blog/{slug}/edit/{slug}');
// after
$route = new Route('/blog/{slug}/edit/{id}'); Defensive patterns
Strategy: validation
Validate before calling
$vars = [];
preg_match_all('/\{(!)?([^}]+)\}/', $route->getPath().' '.$route->getHost(), $m);
foreach ($m[2] as $var) {
if (in_array($var, $vars, true)) {
throw new \InvalidArgumentException("Variable '$var' is used more than once.");
}
$vars[] = $var;
} Try / catch
try {
(new RouteCompiler())->compile($route);
} catch (\LogicException $e) {
// deduplicate/rename placeholders before registering the route
} Prevention
- Uniquely name every placeholder in a route (host and path share the same namespace).
- Copy-paste route segments carefully; rename placeholders immediately after pasting.
- Add a unit test that compiles all routes in RouteCollection during CI.
When it happens
Trigger: Compiling a route like /blog/{slug}/edit/{slug}, or a route whose host and path both contain the same variable, e.g. host '{subdomain}.example.com' with path '/{subdomain}/page'.
Common situations: Copy-pasting path segments and forgetting to rename the placeholder; templated route generation that appends the same parameter twice; combining host and path parameters with the same name.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Parameter " " for route " " must match " " (" " given) to…
- Parameters for route
- Route aliases cannot be used on non-invokable class
- The " ()" method must not be called.
- The return value in config file
AI-assisted analysis of symfony/routing@83fa223250 (2026-09-14).
Data as JSON: /api/errors/21d058296ff98a04.
Report an issue: GitHub.
Appendix: source
Thrown at RouteCompiler.php:150
$pos = $match[0][1] + \strlen($match[0][0]);
if (!\strlen($precedingText)) {
$precedingChar = '';
} elseif ($useUtf8) {
preg_match('/.$/u', $precedingText, $precedingChar);
$precedingChar = $precedingChar[0];
} else {
$precedingChar = substr($precedingText, -1);
}
$isSeparator = '' !== $precedingChar && str_contains(static::SEPARATORS, $precedingChar);
// A PCRE subpattern name must start with a non-digit. Also a PHP variable cannot start with a digit so the
// variable would not be usable as a Controller action argument.
if (preg_match('/^\d/', $varName)) {
throw new \DomainException(\sprintf('Variable name "%s" cannot start with a digit in route pattern "%s". Please use a different name.', $varName, $pattern));
}
if (\in_array($varName, $variables)) {
throw new \LogicException(\sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $pattern, $varName));
}
if (\strlen($varName) > self::VARIABLE_MAXIMUM_LENGTH) {
throw new \DomainException(\sprintf('Variable name "%s" cannot be longer than %d characters in route pattern "%s". Please use a shorter name.', $varName, self::VARIABLE_MAXIMUM_LENGTH, $pattern));
}
if ($isSeparator && $precedingText !== $precedingChar) {
$tokens[] = ['text', substr($precedingText, 0, -\strlen($precedingChar))];
} elseif (!$isSeparator && '' !== $precedingText) {
$tokens[] = ['text', $precedingText];
}
$regexp = $route->getRequirement($varName);
if (null === $regexp) {
$followingPattern = substr($pattern, $pos);
// Find the next static character after the variable that functions as a separator. By default, this separator and '/'
// are disallowed for the variable. This default requirement makes sure that optional variables can be matched at all
// and that the generating-matching-combination of URLs unambiguous, i.e. the params used for generating the URL areView on GitHub (pinned to 83fa223250)