symfony/http-kernel · error · LogicException

Could not resolve the argument typed

Error message

Could not resolve the argument typed "%s". Valid types are "array", "string" or "%s".

What it means

RequestHeaderValueResolver handles #[MapHeader]/header-attribute arguments and only supports argument types string, array, or Symfony\Component\HttpFoundation\AcceptHeader. It throws LogicException when the argument type is anything else that is not even class/interface-like, or is null/variadic — i.e. a type the resolver can never construct from a header.

Solutions

  1. Type the argument as string or array (AcceptHeader for Accept-style headers).
  2. Cast manually: take the string and convert to int/bool in the controller body.
  3. Fix the class name if the type was meant to be an existing class/interface supported by the resolver.

Example fix

// before
public function index(#[MapHeader('x-page')] int $page) {}
// after
public function index(#[MapHeader('x-page')] string $page) {}
$page = (int) $page;
Defensive patterns

Strategy: type-guard

Validate before calling

$t = $param->getType();
if (!$t instanceof \ReflectionNamedType || !in_array($t->getName(), ['string','array',\Symfony\Component\HttpFoundation\AcceptHeader::class], true)) { /* retype argument */ }

Type guard

function isHeaderArgumentSupported(\ReflectionParameter $p): bool
{
    $t = $p->getType();
    return $t instanceof \ReflectionNamedType
        && !$p->isVariadic()
        && in_array($t->getName(), ['string','array',\Symfony\Component\HttpFoundation\AcceptHeader::class], true);
}

Try / catch

try { $args = $resolver->getArguments($request, $controller); } catch (\LogicException $e) { /* retype header argument to string/array/AcceptHeader */ }

Prevention

When it happens

Trigger: Declaring #[MapHeader] (or legacy header mapping) on an argument typed int/bool/float, an untyped argument, a variadic argument, or a class that does not exist in the container-aware check (class_exists/interface_exists false).

Common situations: Assuming headers are auto-cast to int/bool like query params; expecting custom DTOs from headers; typos in use-statements leading to nonexistent class names; upgrading code that previously resolved other scalar types.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at Controller/ArgumentResolver/RequestHeaderValueResolver.php:36

use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NearMissValueResolverException;

final class RequestHeaderValueResolver implements ValueResolverInterface, SourceValueResolverInterface
{
    public function resolve(Request $request, ArgumentMetadata $argument): array
    {
        if (!$attribute = $argument->getAttributesOfType(MapRequestHeader::class)[0] ?? null) {
            return [];
        }

        $type = $argument->getType();
        $name = $attribute->name ?? strtolower(preg_replace('/[a-z]\K[A-Z]/', '-$0', $argument->getName()));

        if (!\in_array($type, ['string', 'array', AcceptHeader::class])) {
            if (null === $type || $argument->isVariadic() || !class_exists($type) && !interface_exists($type)) {
                throw new \LogicException(\sprintf('Could not resolve the argument typed "%s". Valid types are "array", "string" or "%s".', $type, AcceptHeader::class));
            }

            if (!$request->headers->has($name)) {
                if ($argument->isNullable() || $argument->hasDefaultValue()) {
                    return [];
                }

                throw HttpException::fromStatusCode($attribute->validationFailedStatusCode, \sprintf('Missing header "%s".', $name));
            }

            // Stage the raw header under the argument name so that a resolver able to build this type,
            // such as DateTimeValueResolver or UidValueResolver, picks it up from the attributes.
            $request->attributes->set($argument->getName(), $request->headers->get($name));

            throw new NearMissValueResolverException(\sprintf('#[MapRequestHeader] cannot build controller argument "$%s" of type "%s" by itself; no resolver converted the staged value.', $argument->getName(), $type));
        }

        $value = null;

View on GitHub (pinned to aa3a39d728)