symfony/routing · error · InvalidArgumentException
A placeholder name must be a string
Error message
A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s::%s()"?
What it means
AttributeClassLoader::addRoute validates that every route requirement key is a placeholder string. When an attribute requirement is passed as a list (e.g. #[Route(..., requirements: ['\\d+'])]) the key is an integer, so the loader throws InvalidArgumentException naming the route, class and method.
Solutions
- Give each requirement an explicit string key matching the route placeholder: requirements: ['id' => '\d+']
- Verify every requirements entry has a named key on the #[Route]/#[RouteCollision...] attribute
- Check the class-level #[Route] attribute globals too, since requirements are merged with globals
Example fix
// before
#[Route('/blog/{id}', requirements: ['\d+'])]
// after
#[Route('/blog/{id}', requirements: ['id' => '\d+'])] Defensive patterns
Strategy: validation
Validate before calling
foreach ($attr->requirements as $k => $v) { if (is_int($k)) throw new \InvalidArgumentException("Requirement for placeholder '$v' must use a named key"); } Type guard
function hasStringRequirementKeys(array $requirements): bool { foreach ($requirements as $k => $v) { if (!is_string($k)) return false; } return true; } Prevention
- Always write requirements as placeholder => pattern maps
- Grep codebase for requirements: with unkeyed entries
- Add static analysis (e.g. PHPStan rule) flagging integer-keyed requirement arrays
When it happens
Trigger: Declaring an attribute route with a requirements array that uses implicit integer keys, e.g. requirements: ['/d+'] instead of ['id' => '/d+'], so the requirement value has no placeholder name to match against.
Common situations: Migrating from YAML/XML where requirements could be positional; typos like requirements: ['\d+']; refactoring that dropped the placeholder key; copying a route definition and losing the named key.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- A placeholder name must be a string
- Routing requirement for
- Invalid characters found in deprecation template.
- 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/18e53e145c24c760.
Report an issue: GitHub.
Appendix: source
Thrown at Loader/AttributeClassLoader.php:158
}
/**
* @param RouteAttribute $attr or an object that exposes a similar interface
*/
protected function addRoute(RouteCollection $collection, object $attr, array $globals, \ReflectionClass $class, \ReflectionMethod $method): void
{
if ($attr->envs && !\in_array($this->env, $attr->envs, true)) {
return;
}
$name = $attr->name ?? $this->getDefaultRouteName($class, $method);
$name = $globals['name'].$name;
$requirements = $attr->requirements;
foreach ($requirements as $placeholder => $requirement) {
if (\is_int($placeholder)) {
throw new \InvalidArgumentException(\sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s::%s()"?', $placeholder, $requirement, $name, $class->getName(), $method->getName()));
}
}
$defaults = array_replace($globals['defaults'], $attr->defaults);
$requirements = array_replace($globals['requirements'], $requirements);
$options = array_replace($globals['options'], $attr->options);
$schemes = array_unique(array_merge($globals['schemes'], $attr->schemes));
$methods = array_unique(array_merge($globals['methods'], $attr->methods));
$host = $attr->host ?? $globals['host'];
$condition = $attr->condition ?? $globals['condition'];
$priority = $attr->priority ?? $globals['priority'];
$path = $attr->path;
$prefix = $globals['localized_paths'] ?: $globals['path'];
$paths = [];
if (\is_array($path)) {View on GitHub (pinned to 83fa223250)