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" in "%s"?
What it means
getGlobals validates requirement keys coming from a class-level #[Route] attribute before merging them into globals. Integer (positional) keys mean the requirement was given without a placeholder name, so it throws InvalidArgumentException naming the class.
Solutions
- Add explicit placeholder keys to the class-level #[Route] requirements
- Check each #[Route] attribute on the controller class for named requirement keys
- Remember requirements are merged with method-level ones; both sides need string keys
Example fix
// before
#[Route('/blog', requirements: ['\d+'])]
// after
#[Route('/blog', requirements: ['page' => '\d+'])] Defensive patterns
Strategy: validation
Validate before calling
foreach ($classAttr->requirements as $k => $v) { if (is_int($k)) throw new \InvalidArgumentException('Class-level requirement needs named key'); } Type guard
function allRequirementsNamed(array $requirements): bool { return arrayevery(fn($k) => is_string($k), array_keys($requirements)); } Try / catch
try { $routes = $loader->load($file); } catch (\InvalidArgumentException $e) { if (str_contains($e->getMessage(), 'placeholder name must be a string')) { /* fix class attribute */ } throw $e; } Prevention
- Never use positional requirement arrays, even on class-level #[Route]
- Code-review checklist item for requirements keys
- Static analysis rule for integer keys in requirements
When it happens
Trigger: A controller class annotated #[Route(path: '/blog', requirements: ['\d+'])] with a positional requirement, triggering validation of class-level globals during load().
Common situations: Missing named key on class-level requirements; assuming class-level requirements may be positional; copy-paste of a requirement array without its keys.
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/7220c98239d48d70.
Report an issue: GitHub.
Appendix: source
Thrown at Loader/AttributeClassLoader.php:330
if (null !== $attr->methods) {
$globals['methods'] = $attr->methods;
}
if (null !== $attr->host) {
$globals['host'] = $attr->host;
}
if (null !== $attr->condition) {
$globals['condition'] = $attr->condition;
}
$globals['priority'] = $attr->priority ?? 0;
$globals['env'] = $attr->envs;
foreach ($globals['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" in "%s"?', $placeholder, $requirement, $class->getName()));
}
}
}
return $globals;
}
private function resetGlobals(): array
{
return [
'path' => null,
'localized_paths' => [],
'requirements' => [],
'options' => [],
'defaults' => [],
'schemes' => [],
'methods' => [],
'host' => '',View on GitHub (pinned to 83fa223250)