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

  1. Use only scalars (string, int, float, bool, null) and arrays of scalars in defaults/requirements/options
  2. If you need an object, store a scalar identifier in the route and resolve the object in the controller/service
  3. 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

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


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)