symfony/routing · error · InvalidArgumentException
Symfony\Component\Routing\Route cannot contain objects, but
Error message
Symfony\Component\Routing\Route cannot contain objects, but "%s" given.
What it means
CompiledUrlMatcherDumper::export() serializes route data (defaults, requirements, host tokens, etc.) into PHP code for the compiled matcher class. Route values must be scalars or arrays of scalars; objects are not representable, so any object triggers this InvalidArgumentException.
Solutions
- Use only scalars (string, int, float, bool, null) and arrays of scalars in defaults/requirements/options
- If you need an object, store a scalar identifier in the route and resolve the object in the controller/service
- Dump debug with get_debug_type() on the offending default before compiling
Example fix
// before
$route->setDefault('date', new \DateTimeImmutable('today'));
// after
$route->setDefault('date', (new \DateTimeImmutable('today'))->format(\DateTimeInterface::ATOM)); Defensive patterns
Strategy: validation
Validate before calling
foreach (array_merge($route->getDefaults(), $route->getRequirements()) as $k => $v) { if (is_object($v)) throw new \LogicException("Route value '$k' must be scalar, got ".get_debug_type($v)); } Type guard
function isScalarTree(mixed $v): bool { return is_scalar($v) || is_null($v) || (is_array($v) && array_all($v, fn($x) => isScalarTree($x))); } Try / catch
try { $dumper->dump(); } catch (\InvalidArgumentException $e) { if (str_contains($e->getMessage(), 'cannot contain objects')) { /* find the object default */ } throw $e; } Prevention
- Keep route defaults/requirements/options strictly scalar
- Serialize objects to strings/ids before setDefault()
- Add a compile-time assertion that all route values pass a scalar-tree check
When it happens
Trigger: A route default, requirement, or option containing an object — e.g. 'defaults' => ['locale' => new SomeObject()] — or a Closure stored in defaults (commonly an accidentally-passed controller instance or an object implementing __toString into defaults/requirements).
Common situations: Defining routes programmatically and passing non-scalar defaults (e.g. a DateTime, enum without conversion, or Closure); passing an object into ->setRequirement() or options; framework configs where a parameter resolves to an object service instead of a scalar.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot serialize Loader\Configurator\ImportConfigurator
- 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.
AI-assisted analysis of symfony/routing@83fa223250 (2026-09-14).
Data as JSON: /api/errors/3a9467e99ced153a.
Report an issue: GitHub.
Appendix: source
Thrown at Matcher/Dumper/CompiledUrlMatcherDumper.php:474
return $this->expressionLanguage;
}
private function indent(string $code, int $level = 1): string
{
return preg_replace('/^./m', str_repeat(' ', $level).'$0', $code);
}
/**
* @internal
*/
public static function export(mixed $value): string
{
if (null === $value) {
return 'null';
}
if (\is_object($value)) {
throw new \InvalidArgumentException(\sprintf('Symfony\Component\Routing\Route cannot contain objects, but "%s" given.', get_debug_type($value)));
}
if (!\is_array($value)) {
return str_replace("\n", '\'."\n".\'', var_export($value, true));
}
if (!$value) {
return '[]';
}
$i = 0;
$export = '[';
foreach ($value as $k => $v) {
if ($i === $k) {
++$i;
} else {
$export .= self::export($k).' => ';
if (\is_int($k) && $i < $k) {View on GitHub (pinned to 83fa223250)