{"record":{"id":"b9d24fb2abc61606","repo":"symfony/http-kernel","slug":"missing-query-parameter-s","errorCode":null,"errorMessage":"Missing query parameter \"%s\".","messagePattern":"Missing query parameter \"(.+?)\"\\.","errorType":"validation","errorClass":"HttpException","httpStatus":null,"severity":"error","filePath":"Controller/ArgumentResolver/QueryParameterValueResolver.php","lineNumber":50,"sourceCode":" * @author Ionut Enache <i.ovidiuenache@yahoo.com>\n */\nfinal class QueryParameterValueResolver implements ValueResolverInterface, SourceValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        if (!$attribute = $argument->getAttributesOfType(MapQueryParameter::class)[0] ?? null) {\n            return [];\n        }\n\n        $name = $attribute->name ?? $argument->getName();\n        $validationFailedCode = $attribute->validationFailedStatusCode;\n\n        if (!$request->query->has($name)) {\n            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        }","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/symfony/http-kernel/blob/aa3a39d7286a62cdfea98f0e69c651a3da6e36cf/Controller/ArgumentResolver/QueryParameterValueResolver.php#L32-L68","documentation":"This HttpException is thrown by QueryParameterValueResolver::resolve() when a controller argument annotated with #[MapQueryParameter] is not present in the request's query string, and the argument is neither nullable nor has a default value. The library throws it to fail the request early with a 4xx status (configurable via validationFailedStatusCode, 422 by default) instead of passing null into the controller. It signals a client-side problem: the caller omitted a required query parameter.","triggerScenarios":"A controller method declares e.g. function list(#[MapQueryParameter] int $page) and the request URL lacks ?page=; or the parameter name differs from the argument name and no custom name is set via #[MapQueryParameter(name: '...')]; or the client sends the parameter in the POST body instead of the query string; or a nullable/defaulted argument exists but isVariadic with no value present in an unsupported combination.","commonSituations":"Frontend forgot to append the query parameter on an API call; a link/template builds a URL without the parameter; a rename of the query key in the client was not mirrored in the controller (or vice versa); clients sending data as form body while the controller expects query string; reverse proxies or redirects stripping the query string.","solutions":["Append the missing parameter to the request URL, e.g. /api/items?page=1","Verify the query parameter name matches the controller argument name (or pass the explicit name: #[MapQueryParameter(name: 'per_page')])","If the parameter is truly optional, make the argument nullable or give it a default: function list(#[MapQueryParameter] ?int $page = null)","Confirm the client sends it in the query string, not the request body","Set validationFailedStatusCode on the attribute if a different HTTP status (e.g. 400) is desired"],"exampleFix":"// before\n#[Route('/items')]\npublic function list(#[MapQueryParameter] int $page) { ... }\n// request: GET /items  -> 422 Missing query parameter \"page\"\n\n// after\n#[Route('/items')]\npublic function list(#[MapQueryParameter] ?int $page = null) { ... }\n// or client calls GET /items?page=1","handlingStrategy":"validation","validationCode":"const params = new URLSearchParams({ page: '1' });\nif (!params.has('page')) throw new Error('page query parameter is required');\nfetch(`/items?${params}`);","typeGuard":"function hasQueryParam(url: URL, name: string): boolean {\n  return url.searchParams.has(name);\n}","tryCatchPattern":"try {\n  const res = await fetch('/items');\n  if (res.status === 422) {\n    const body = await res.text();\n    if (body.includes('Missing query parameter')) { /* add param and retry */ }\n  }\n} catch (e) { /* network error */ }","preventionTips":["Build request URLs through a typed helper that asserts required query params","Keep query parameter names in a shared constant between client and controller","Make truly optional params nullable or defaulted in the controller signature","Add an integration test asserting each endpoint's required query params"],"tags":["http","symfony","query-parameters","validation"],"backgroundTag":"missing-required-argument","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"}