symfony/routing · error · InvalidArgumentException

The "type" key for the route definition

Error message

The "type" key for the route definition "%s" in "%s" is unsupported. It is only available for imports in combination with the "resource" key.

What it means

Symfony's routing loader rejects a 'type' key on a route entry that does not also define 'resource'. The 'type' key exists only to select a custom loader for imports; a plain route definition (with 'path') has no loader to select, so the key is meaningless and the validate() method of ContentLoaderTrait throws InvalidArgumentException to catch the config mistake early.

Solutions

  1. Remove the 'type' key from the route definition — plain routes do not need a loader type
  2. If a loader type is actually needed, change the entry to an import: keep 'type' and add a 'resource' key
  3. Remove 'path' and restore 'resource' if the entry was meant to import routes

Example fix

# before
app_blog:
    path: /blog
    type: attribute

# after
app_blog:
    path: /blog
    controller: App\Controller\BlogController::index
Defensive patterns

Strategy: validation

Validate before calling

if (isset($config['type']) && !isset($config['resource'])) {
    throw new \InvalidArgumentException(sprintf('Route "%s": "type" requires a "resource" key (import).', $name));
}

Type guard

function isImportWithValidType(array $config): bool { return !isset($config['type']) || isset($config['resource']); }

Try / catch

try { $collection = $loader->load($file, 'yaml'); } catch (\InvalidArgumentException $e) { /* fix routing config referenced in $e->getMessage() */ }

Prevention

When it happens

Trigger: Loading a YAML/XML/PHP routing file whose entry has 'type' (e.g. type: attribute) but no 'resource' key — i.e. a direct route definition carrying a loader type.

Common situations: Copy-pasting an import block and editing 'resource' into 'path' while leaving 'type' behind; upgrading from old configs where 'type: annotation' was tolerated; hand-written routes that mimicked import syntax.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of symfony/routing@83fa223250 (2026-09-14). Data as JSON: /api/errors/953d2ffba26c9485. Report an issue: GitHub.

Appendix: source

Thrown at Loader/ContentLoaderTrait.php:223

     */
    private function validate(mixed $config, string $name, string $path): void
    {
        if (!\is_array($config)) {
            throw new \InvalidArgumentException(\sprintf('The definition of "%s" in "%s" must be an array.', $name, $path));
        }
        if (isset($config['alias'])) {
            $this->validateAlias($config, $name, $path);

            return;
        }
        if ($extraKeys = array_diff(array_keys($config), self::AVAILABLE_KEYS)) {
            throw new \InvalidArgumentException(\sprintf('The routing file "%s" contains unsupported keys for "%s": "%s". Expected one of: "%s".', $path, $name, implode('", "', $extraKeys), implode('", "', self::AVAILABLE_KEYS)));
        }
        if (isset($config['resource']) && isset($config['path'])) {
            throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "resource" key and the "path" key for "%s". Choose between an import and a route definition.', $path, $name));
        }
        if (!isset($config['resource']) && isset($config['type'])) {
            throw new \InvalidArgumentException(\sprintf('The "type" key for the route definition "%s" in "%s" is unsupported. It is only available for imports in combination with the "resource" key.', $name, $path));
        }
        if (!isset($config['resource']) && !isset($config['path'])) {
            throw new \InvalidArgumentException(\sprintf('You must define a "path" for the route "%s" in file "%s".', $name, $path));
        }
        if (isset($config['controller']) && isset($config['defaults']['_controller'])) {
            throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "controller" key and the defaults key "_controller" for "%s".', $path, $name));
        }
        if (isset($config['stateless']) && isset($config['defaults']['_stateless'])) {
            throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "stateless" key and the defaults key "_stateless" for "%s".', $path, $name));
        }
        if (isset($config['firewall']) && isset($config['defaults']['_firewall'])) {
            throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "firewall" key and the defaults key "_firewall" for "%s".', $path, $name));
        }
    }

    /**
     * Validates that an alias definition only carries the `alias` and `deprecated` keys.
     *

View on GitHub (pinned to 83fa223250)