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

  1. Change the argument type to one of array, string, int, float, bool, \Symfony\Component\Uid\Uid-type (uid), or a backed enum.
  2. For non-backed enums, add a backing type (int|string) to the enum.
  3. 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

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


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)