symfony/routing · error · InvalidParameterException

Default "_query" must be an array of query parameters for…

Error message

Default "_query" must be an array of query parameters for route "%s".

What it means

A route may define a default '_query' holding extra query parameters appended to generated URLs. This error means $defaults['_query'] exists but is not an array, so it cannot be merged as query parameters.

Solutions

  1. Change the _query default to a mapping: defaults: { _query: { foo: 'bar' } }.
  2. Remove _query from defaults if not needed.
  3. Check YAML indentation so _query is parsed as a map, not a string.

Example fix

// before (routes.yaml)
defaults: { _controller: 'App\Controller::index', _query: 'foo=bar' }
// after
defaults: { _controller: 'App\Controller::index', _query: { foo: 'bar' } }
Defensive patterns

Strategy: validation

Validate before calling

if (isset($defaults['_query']) && !is_array($defaults['_query'])) {
    throw new LogicException('Route default "_query" must be an array.');
}

Type guard

function hasValidDefaultQuery(array $defaults): bool { return !isset($defaults['_query']) || is_array($defaults['_query']); }

Try / catch

use Symfony\Component\Routing\Exception\InvalidParameterException;
try { $url = $generator->generate($name); } catch (InvalidParameterException $e) { $url = '/'; }

Prevention

When it happens

Trigger: Route definition sets defaults: { _query: 'something' } (or a scalar/null) and doGenerate() runs during generate().

Common situations: Misconfigured route defaults in YAML/PHP config (quoted string instead of mapping); controller attribute passing a scalar _query default.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at Generator/UrlGenerator.php:149

            } elseif (!isset($parameters['_locale'])) {
                $parameters['_locale'] = $defaults['_locale'];
            }
        }

        return $this->doGenerate($variables, $defaults, $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostTokens(), $route->getSchemes());
    }

    /**
     * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
     * @throws InvalidParameterException           When a parameter value for a placeholder is not correct because
     *                                             it does not match the requirement
     */
    protected function doGenerate(array $variables, array $defaults, array $requirements, array $tokens, array $parameters, string $name, int $referenceType, array $hostTokens, array $requiredSchemes = []): string
    {
        $defaultQuery = $defaults['_query'] ?? [];

        if (!\is_array($defaultQuery)) {
            throw new InvalidParameterException(\sprintf('Default "_query" must be an array of query parameters for route "%s".', $name));
        }

        $queryParameters = [];

        if (isset($parameters['_query'])) {
            if (\is_array($parameters['_query'])) {
                $queryParameters = $parameters['_query'];
                unset($parameters['_query']);
            } else {
                throw new InvalidParameterException('Parameter "_query" must be an array of query parameters.');
            }
        }

        $variables = array_flip($variables);
        $mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters);

        // all params must be given
        if ($diff = array_diff_key($variables, $mergedParams)) {

View on GitHub (pinned to 83fa223250)