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
- Type the argument as string or array (AcceptHeader for Accept-style headers).
- Cast manually: take the string and convert to int/bool in the controller body.
- 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
- Type header arguments as string or array only
- Cast to int/bool manually inside the controller
- Use AcceptHeader for content-negotiation headers
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
- 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…
- #[MapQueryParameter] cannot be used on controller argument
- Could not resolve the "$
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)