symfony/http-kernel · error · InvalidArgumentException

" ::resolve()" must yield at most one value for…

Error message

"%s::resolve()" must yield at most one value for non-variadic arguments.

What it means

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.

Solutions

  1. Change the resolver to yield at most one value for non-variadic arguments; return/yield nothing to signal a near miss.
  2. If multiple values are legitimate, declare the controller argument variadic (e.g. Foo ...$foos).
  3. Aggregate candidates internally and pick one before yielding.

Example fix

// before
public function resolve(Request $request, ArgumentMetadata $argument): \Generator
{
    foreach ($candidates as $c) {
        yield $c; // throws when >1 and argument not variadic
    }
}
// after
public function resolve(Request $request, ArgumentMetadata $argument): \Generator
{
    if ($candidate = $this->pickBest($candidates)) {
        yield $candidate;
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// In your custom resolver:
$count = 0;
foreach ($this->doResolve($request, $argument) as $v) { if (++$count > 1 && !$argument->isVariadic()) { throw new \AssertionError('Resolver yielded multiple values'); } }

Try / catch

try { $args = $argumentResolver->getArguments($request, $callable); } catch (\InvalidArgumentException $e) { /* check resolver generator yields */ }

Prevention

When it happens

Trigger: A custom ValueResolverInterface::resolve() implemented with yield emits two or more values while the target controller argument is not declared variadic (...$args).

Common situations: 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.

Related errors


AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13). Data as JSON: /api/errors/c190e0ef38eaf859. Report an issue: GitHub.

Appendix: source

Thrown at Controller/ArgumentResolver.php:115

            $valueResolverExceptions = [];
            foreach ($argumentValueResolvers as $name => $resolver) {
                if (isset($disabledResolvers[\is_int($name) ? $resolver::class : $name])) {
                    continue;
                }

                try {
                    $count = 0;
                    foreach ($resolver->resolve($request, $metadata) as $argument) {
                        ++$count;
                        $arguments[] = $argument;
                    }
                } catch (NearMissValueResolverException $e) {
                    $valueResolverExceptions[] = $e;
                }

                if (1 < $count && !$metadata->isVariadic()) {
                    throw new \InvalidArgumentException(\sprintf('"%s::resolve()" must yield at most one value for non-variadic arguments.', get_debug_type($resolver)));
                }

                if ($count) {
                    // continue to the next controller argument
                    continue 2;
                }
            }

            $reasons = array_map(static fn (NearMissValueResolverException $e) => $e->getMessage(), $valueResolverExceptions);
            if (!$reasons) {
                $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.';
            }

            $reasonCounter = 1;
            if (\count($reasons) > 1) {
                foreach ($reasons as $i => $reason) {
                    $reasons[$i] = $reasonCounter.') '.$reason;
                    ++$reasonCounter;

View on GitHub (pinned to aa3a39d728)