{"record":{"id":"ebe16fdcef485c29","repo":"symfony/http-kernel","slug":"invalid-query-parameter-s","errorCode":null,"errorMessage":"Invalid query parameter \"%s\".","messagePattern":"Invalid query parameter \"(.+?)\"\\.","errorType":"validation","errorClass":"HttpException","httpStatus":null,"severity":"error","filePath":"Controller/ArgumentResolver/QueryParameterValueResolver.php","lineNumber":64,"sourceCode":"            if ($argument->isNullable() || $argument->hasDefaultValue()) {\n                return [];\n            }\n\n            throw HttpException::fromStatusCode($validationFailedCode, \\sprintf('Missing query parameter \"%s\".', $name));\n        }\n\n        $value = $request->query->all()[$name];\n        $type = $argument->getType();\n\n        if (null === $attribute->filter && 'array' === $type) {\n            if (!$argument->isVariadic()) {\n                return [(array) $value];\n            }\n\n            $filtered = array_values(array_filter((array) $value, \\is_array(...)));\n\n            if ($filtered !== $value && !($attribute->flags & \\FILTER_NULL_ON_FAILURE)) {\n                throw HttpException::fromStatusCode($validationFailedCode, \\sprintf('Invalid query parameter \"%s\".', $name));\n            }\n\n            return $filtered;\n        }\n\n        $options = [\n            'flags' => $attribute->flags | \\FILTER_NULL_ON_FAILURE,\n            'options' => $attribute->options,\n        ];\n\n        if ('array' === $type || $argument->isVariadic()) {\n            $value = (array) $value;\n            $options['flags'] |= \\FILTER_REQUIRE_ARRAY;\n        } else {\n            $options['flags'] |= \\FILTER_REQUIRE_SCALAR;\n        }\n\n        $uidType = null;","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/symfony/http-kernel/blob/aa3a39d7286a62cdfea98f0e69c651a3da6e36cf/Controller/ArgumentResolver/QueryParameterValueResolver.php#L46-L82","documentation":"Thrown when a #[MapQueryParameter] argument typed as array (non-variadic, no custom filter) receives query values that are not all arrays. The resolver filters the value keeping only elements that are themselves arrays (array_filter with is_array); if any element was dropped and FILTER_NULL_ON_FAILURE was not set, the whole parameter is rejected. In practice this fires when a plain scalar or list of scalars is sent for a parameter declared as array-of-array.","triggerScenarios":"Controller declares #[MapQueryParameter] array $filter and the client sends ?filter=foo (scalar) or ?filter[]=1&filter[]=2 (array of scalars); only nested-array values like filter[a][b]=1 survive the is_array filter, so anything else triggers the throw unless FILTER_NULL_ON_FAILURE is passed in the attribute flags.","commonSituations":"Client sends a simple list (?ids[]=1&ids[]=2) while the controller argument is typed array with no variadic and no filter — the developer expected a flat array but Symfony's unfiltered array branch demands arrays-of-arrays; version migrations where behavior around typed array query params changed.","solutions":["Send nested query syntax producing arrays of arrays, e.g. ?filter[from]=1&filter[to]=2 becomes filter as an array of arrays only if each value is itself an array — or restructure the URL","If a flat array is intended, make the argument variadic (#[MapQueryParameter] array ...$ids) or add an explicit filter, e.g. #[MapQueryParameter(filter: FILTER_DEFAULT)] which routes through filter_var instead of this array branch","Pass flags: FILTER_NULL_ON_FAILURE in #[MapQueryParameter] to get null/dropped values instead of a 4xx","Change the controller type to string/int and split manually if only one value is expected"],"exampleFix":"// before\npublic function search(#[MapQueryParameter] array $tags) { ... }\n// request: GET /search?tags=php  -> 422 Invalid query parameter \"tags\"\n\n// after\npublic function search(#[MapQueryParameter(filter: \\FILTER_DEFAULT)] array $tags) { ... }\n// request: GET /search?tags[]=php&tags[]=symfony works","handlingStrategy":"validation","validationCode":"// send nested arrays only if the argument is plain `array`, else send flat lists with a filter configured\nconst usp = new URLSearchParams();\n['php','symfony'].forEach(t => usp.append('tags[]', t)); // flat list; pair with filter: FILTER_DEFAULT on the server","typeGuard":"function isArrayOfArrays(v: unknown): v is unknown[][] {\n  return Array.isArray(v) && v.every(Array.isArray);\n}","tryCatchPattern":"try {\n  const res = await fetch(url);\n  if (res.status === 422 && (await res.text()).includes('Invalid query parameter')) {\n    // reshape the query value (scalar -> nested array or flat list) and retry\n  }\n} catch (e) {}","preventionTips":["Match client query syntax to the controller's declared type before shipping","Prefer variadic arguments or an explicit filter for flat list parameters","Document each endpoint's expected query-string shape","Add contract tests covering array-shaped query params"],"tags":["http","symfony","query-parameters","validation"],"backgroundTag":"invalid-query-parameter","analyzedSha":"aa3a39d7286a62cdfea98f0e69c651a3da6e36cf","analyzedAt":"2026-09-13T18:03:36.509Z","contentChangedAt":"2026-09-13T18:03:36.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}