symfony/http-kernel · error · LogicException
You can only pin one resolver per argument, but argument "$
Error message
You can only pin one resolver per argument, but argument "$%s" of "%s()" has more.
What it means
ArgumentResolver::getArguments() enforces that when argument attribute pinning (#[AutowireResolver]-style named resolvers) is used, at most one resolver may be pinned per argument unless exactly one of them is a SourceValueResolverInterface. A LogicException is thrown when multiple pinned resolvers are given and none/many qualify as the single source.
Solutions
- Remove all but one pinned resolver attribute from the argument.
- If conversion chaining is intended, ensure exactly one pinned resolver implements SourceValueResolverInterface and it is the value source.
- Move secondary resolution logic into a custom resolver that chains internally instead of pinning multiple.
Example fix
// before
public function show(#[CurrentUser] #[MapQueryString] User $user, #[MapDateTime] \DateTime $dt) {}
// after
public function show(#[CurrentUser] User $user, #[MapQueryString] QueryDto $q) {} Defensive patterns
Strategy: validation
Validate before calling
$attrs = $reflectionParameter->getAttributes();
$pinned = array_filter($attrs, fn($a) => str_contains($a->getName(), 'Resolver') || in_array($a->getName(), [MapQueryParameter::class, MapRequestPayload::class, CurrentUser::class], true));
if (count($pinned) > 1) { throw new \AssertionError('Only one pinned resolver allowed per argument'); } Try / catch
try { $args = $resolver->getArguments($request, $controller); } catch (\LogicException $e) { /* review stacked resolver attributes */ } Prevention
- Never stack two resolver attributes on the same controller argument
- Check SourceValueResolverInterface semantics when chaining resolvers
- Review controller signatures in code review for attribute conflicts
When it happens
Trigger: Annotating a controller argument with two or more pinned resolver attributes (e.g. two #[ValueResolver] attributes or a pinned combination) where the resolvers are all converters (none is a SourceValueResolver) or more than one is a source resolver.
Common situations: Stacking #[CurrentUser] with #[MapRequestPayload] or similar on the same argument; copy-pasting resolver attributes; Symfony 6.1+ pinned-resolver feature used with legacy resolvers that are not source resolvers.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- " ::resolve()" must yield at most one value for…
- Controller " " requires the "$ " argument that could not be…
- #[MapQueryParameter] cannot be used on controller argument
- Could not resolve the argument typed
- Could not resolve the "$
AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13).
Data as JSON: /api/errors/8f34339404690f80.
Report an issue: GitHub.
Appendix: source
Thrown at Controller/ArgumentResolver.php:74
$disabledResolvers = [];
if ($this->namedResolvers && $attributes = $metadata->getAttributesOfType(ValueResolver::class, $metadata::IS_INSTANCEOF)) {
$resolverNames = [];
foreach ($attributes as $attribute) {
if ($attribute->disabled) {
$disabledResolvers[$attribute->resolver] = true;
} else {
$resolverNames[] = $attribute->resolver;
}
}
if ($resolverNames) {
// Several resolvers can be pinned when exactly one of them selects the source of
// the value: that one runs first, the others convert what it stages.
$sourceNames = array_values(array_filter($resolverNames, fn ($name) => $this->namedResolvers->has($name) && $this->namedResolvers->get($name) instanceof SourceValueResolverInterface));
if (1 < \count($resolverNames) && 1 !== \count($sourceNames)) {
throw new \LogicException(\sprintf('You can only pin one resolver per argument, but argument "$%s" of "%s()" has more.', $metadata->getName(), $metadata->getControllerName()));
}
$pinnedResolvers = [];
foreach ([...$sourceNames, ...array_diff($resolverNames, $sourceNames)] as $resolverName) {
if (!$this->namedResolvers->has($resolverName)) {
throw new ResolverNotFoundException($resolverName, $this->namedResolvers instanceof ServiceProviderInterface ? array_keys($this->namedResolvers->getProvidedServices()) : []);
}
$pinnedResolvers[] = $this->namedResolvers->get($resolverName);
}
// A source resolver only selects where the value comes from: keep the whole chain
// behind it so that the resolver able to build the argument type still runs.
$argumentValueResolvers = $sourceNames
? [...$pinnedResolvers, ...$this->argumentValueResolvers]
: [
$pinnedResolvers[0],
new RequestAttributeValueResolver(),View on GitHub (pinned to aa3a39d728)