symfony/http-kernel · error · LogicException
#[MapQueryParameter] cannot be used on controller argument
Error message
#[MapQueryParameter] cannot be used on controller argument "%s$%s" of type "%s"; one of array, string, int, float, bool, uid or \BackedEnum should be used.
What it means
QueryParameterValueResolver resolves controller arguments annotated with #[MapQueryParameter] by mapping the argument's type to a PHP filter. It throws LogicException when the declared type is not one of array, string, int, float, bool, uid, or a BackedEnum, because no filter can validate such a value.
Solutions
- Change the argument type to one of array, string, int, float, bool, \Symfony\Component\Uid\Uid-type (uid), or a backed enum.
- For non-backed enums, add a backing type (int|string) to the enum.
- For objects like DateTime, accept a string and convert inside the controller, or write a custom value resolver.
Example fix
// before
public function list(#[MapQueryParameter] \DateTimeImmutable $since) {}
// after
public function list(#[MapQueryParameter] string $since) {}
$since = new \DateTimeImmutable($since); Defensive patterns
Strategy: type-guard
Validate before calling
$type = $param->getType(); $allowed = ['array','string','int','float','bool']; $ok = $type instanceof \ReflectionNamedType && (in_array($type->getName(), $allowed, true) || is_subclass_of($type->getName(), \BackedEnum::class) || is_subclass_of($type->getName(), \Symfony\Component\Uid\AbstractUid::class));
Type guard
function isMapQueryParameterCompatible(\ReflectionParameter $p): bool
{
$t = $p->getType();
if (!$t instanceof \ReflectionNamedType) return false;
return in_array($t->getName(), ['array','string','int','float','bool'], true)
|| is_subclass_of($t->getName(), \BackedEnum::class)
|| is_subclass_of($t->getName(), \Symfony\Component\Uid\AbstractUid::class);
} Try / catch
try { $args = $resolver->getArguments($request, $controller); } catch (\LogicException $e) { /* retype argument to a supported scalar/backed-enum */ } Prevention
- Only use supported scalar types or backed enums with #[MapQueryParameter]
- Convert strings to DateTime/objects inside the controller
- Prefer int/string-backed enums for filterable query flags
When it happens
Trigger: Using #[MapQueryParameter] on an argument typed as an object (other than \BackedEnum subclass), a UnionType, 'mixed', a non-backed (pure) Enum, or a class like DateTimeImmutable.
Common situations: Mapping query params to DateTime or custom value objects; using enum cases without backing values; forgetting that only int-/string-backed enums are supported; variadic and nullable variants still require supported base types.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- You can only pin one resolver per argument, but argument "$
- " ::resolve()" must yield at most one value for…
- Controller " " requires the "$ " argument that could not be…
- Could not resolve the argument typed
- Controller " " has required constructor arguments and does…
AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13).
Data as JSON: /api/errors/0d2c99b8cf61c830.
Report an issue: GitHub.
Appendix: source
Thrown at Controller/ArgumentResolver/QueryParameterValueResolver.php:117
// Stage the raw value under the argument name so that a resolver able to build this type,
// such as DateTimeValueResolver or EntityValueResolver, picks it up from the attributes.
$request->attributes->set($argument->getName(), $value);
throw new NearMissValueResolverException(\sprintf('#[MapQueryParameter] cannot build controller argument "$%s" of type "%s" by itself; no resolver converted the staged value.', $argument->getName(), $type));
}
$enumType = null;
$filter = match ($type) {
'array' => \FILTER_DEFAULT,
'string' => isset($attribute->options['regexp']) ? \FILTER_VALIDATE_REGEXP : \FILTER_DEFAULT,
'int' => \FILTER_VALIDATE_INT,
'float' => \FILTER_VALIDATE_FLOAT,
'bool' => \FILTER_VALIDATE_BOOL,
'uid' => \FILTER_DEFAULT,
default => match ($enumType = is_subclass_of($type, \BackedEnum::class) ? (new \ReflectionEnum($type))->getBackingType()->getName() : null) {
'int' => \FILTER_VALIDATE_INT,
'string' => \FILTER_DEFAULT,
default => throw new \LogicException(\sprintf('#[MapQueryParameter] cannot be used on controller argument "%s$%s" of type "%s"; one of array, string, int, float, bool, uid or \BackedEnum should be used.', $argument->isVariadic() ? '...' : '', $argument->getName(), $type ?? 'mixed')),
},
};
$value = filter_var($value, $attribute->filter ?? $filter, $options);
if (null !== $enumType && null !== $value) {
$enumFrom = static function ($value) use ($type) {
if (!\is_string($value) && !\is_int($value)) {
return null;
}
try {
return $type::from($value);
} catch (\ValueError) {
return null;
}
};
View on GitHub (pinned to aa3a39d728)