{"record":{"id":"c190e0ef38eaf859","repo":"symfony/http-kernel","slug":"s-resolve-must-yield-at-most-one-value-for-non-variadic","errorCode":null,"errorMessage":"\"%s::resolve()\" must yield at most one value for non-variadic arguments.","messagePattern":"\"(.+?)::resolve\\(\\)\" must yield at most one value for non-variadic arguments\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"Controller/ArgumentResolver.php","lineNumber":115,"sourceCode":"\n            $valueResolverExceptions = [];\n            foreach ($argumentValueResolvers as $name => $resolver) {\n                if (isset($disabledResolvers[\\is_int($name) ? $resolver::class : $name])) {\n                    continue;\n                }\n\n                try {\n                    $count = 0;\n                    foreach ($resolver->resolve($request, $metadata) as $argument) {\n                        ++$count;\n                        $arguments[] = $argument;\n                    }\n                } catch (NearMissValueResolverException $e) {\n                    $valueResolverExceptions[] = $e;\n                }\n\n                if (1 < $count && !$metadata->isVariadic()) {\n                    throw new \\InvalidArgumentException(\\sprintf('\"%s::resolve()\" must yield at most one value for non-variadic arguments.', get_debug_type($resolver)));\n                }\n\n                if ($count) {\n                    // continue to the next controller argument\n                    continue 2;\n                }\n            }\n\n            $reasons = array_map(static fn (NearMissValueResolverException $e) => $e->getMessage(), $valueResolverExceptions);\n            if (!$reasons) {\n                $reasons[] = 'Either the argument is nullable and no null value has been provided, no default value has been provided or there is a non-optional argument after this one.';\n            }\n\n            $reasonCounter = 1;\n            if (\\count($reasons) > 1) {\n                foreach ($reasons as $i => $reason) {\n                    $reasons[$i] = $reasonCounter.') '.$reason;\n                    ++$reasonCounter;","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/symfony/http-kernel/blob/aa3a39d7286a62cdfea98f0e69c651a3da6e36cf/Controller/ArgumentResolver.php#L97-L133","documentation":"ArgumentResolver::getArguments() counts how many values a non-pinned value resolver yields per argument and throws InvalidArgumentException when a resolver's resolve() generator yields more than one value for a non-variadic controller argument. Resolvers are generators precisely so they can signal 'near miss' by yielding nothing; multiple yields are only valid for variadic arguments.","triggerScenarios":"A custom ValueResolverInterface::resolve() implemented with yield emits two or more values while the target controller argument is not declared variadic (...$args).","commonSituations":"Custom resolvers written to 'try' multiple candidate values with multiple yields; adapting old ArgumentValueResolverInterface code that returned arrays with several items; typos where a loop yields per-item instead of returning one.","solutions":["Change the resolver to yield at most one value for non-variadic arguments; return/yield nothing to signal a near miss.","If multiple values are legitimate, declare the controller argument variadic (e.g. Foo ...$foos).","Aggregate candidates internally and pick one before yielding."],"exampleFix":"// before\npublic function resolve(Request $request, ArgumentMetadata $argument): \\Generator\n{\n    foreach ($candidates as $c) {\n        yield $c; // throws when >1 and argument not variadic\n    }\n}\n// after\npublic function resolve(Request $request, ArgumentMetadata $argument): \\Generator\n{\n    if ($candidate = $this->pickBest($candidates)) {\n        yield $candidate;\n    }\n}","handlingStrategy":"validation","validationCode":"// In your custom resolver:\n$count = 0;\nforeach ($this->doResolve($request, $argument) as $v) { if (++$count > 1 && !$argument->isVariadic()) { throw new \\AssertionError('Resolver yielded multiple values'); } }","typeGuard":null,"tryCatchPattern":"try { $args = $argumentResolver->getArguments($request, $callable); } catch (\\InvalidArgumentException $e) { /* check resolver generator yields */ }","preventionTips":["Yield at most one value in resolve(); yield nothing to decline","Declare variadic arguments (...$x) when multiple values are valid","Write unit tests that run resolvers against representative requests"],"tags":["symfony","controller","argument-resolver","generator"],"backgroundTag":"unexpected-response-shape","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"}