symfony/http-foundation · error · BadRequestException
Invalid URI: Host is malformed.
Error message
Invalid URI: Host is malformed.
What it means
Request::create() validates the host component extracted from the URI with self::isHostValid(). If a non-empty host fails that check (disallowed characters or malformed IPv6 literal), the factory refuses to build the Request and throws BadRequestException ('Invalid URI: Host is malformed.'), which maps to an HTTP 400. This blocks host-header injection and DNS-rebinding style URLs at construction time.
Solutions
- Fix the URI so its host is a valid registered name (RFC 1123: letters, digits, hyphens, dots) or a bracketed IPv6 literal, e.g. 'http://my-host.example.com/'.
- Validate the host before calling: parse_url($uri, PHP_URL_HOST) and run the same kind of check (or filter_var($host, FILTER_VALIDATE_DOMAIN)).
- If the value comes from configuration, correct the base-url/host config entry (underscores and spaces are not valid in hostnames).
- For untrusted input, catch BadRequestException from Request::create() and reject the request with a 400.
Example fix
// before
$request = Request::create('http://my_host.example.com/path'); // underscore: invalid
// after
$host = parse_url($uri, PHP_URL_HOST);
if (!preg_match('/^(\[?[a-f0-9:.]+\]?)$|^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i', (string) $host)) {
throw new \InvalidArgumentException('Invalid host in URI');
}
$request = Request::create($uri); Defensive patterns
Strategy: validation
Validate before calling
function hasValidHost(string $uri): bool
{
$host = parse_url($uri, PHP_URL_HOST);
if (null === $host || false === $host || '' === $host) {
return true; // no host component: this specific check does not apply
}
if (preg_match('/^\[.+\]$/', $host)) {
return false !== filter_var(trim($host, '[]'), FILTER_VALIDATE_IP);
}
return (bool) preg_match('/^(?!-)[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.?$/', $host);
}
if (!hasValidHost($uri)) {
throw new \InvalidArgumentException('Invalid host in URI');
} Type guard
function isWellFormedUrl(string $uri): bool
{
$c = parse_url($uri);
return false !== $c && (!isset($c['host']) || '' !== $c['host']);
} Try / catch
try {
$request = Request::create($uri);
} catch (BadRequestException $e) {
if (str_contains($e->getMessage(), 'Host is malformed')) {
return new Response('Unacceptable host in URL.', 400);
}
throw $e;
} Prevention
- Keep hostnames in config RFC-1123 compliant (no underscores, spaces, or commas)
- Use filter_var($host, FILTER_VALIDATE_DOMAIN) on user-supplied hosts before building requests
- For IPv6 targets always wrap the address in square brackets: http://[::1]/
- Add tests for invalid hosts (underscore, bad IPv6 literal) around every code path that accepts external URLs
When it happens
Trigger: Calling Request::create('http://<bad-host>/...') where the host contains characters outside the allowed set (letters, digits, '-', '.', and bracketed IPv6 per isHostValid), e.g. 'http://host_name/' with underscore, 'http://[not-ipv6]/', or hosts with spaces/commas. parse_url() extracted a 'host' key but isHostValid() rejected it at Request.php:405-406.
Common situations: Building requests from user-provided callback/webhook URLs; misconfigured base URLs in config (typo, underscore in hostname); test suites exercising invalid-host handling; SSRF filters that should reject bad hosts before reaching the framework.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid URI: Userinfo is malformed.
- Invalid URI: A URI cannot contain a backslash.
- Invalid URI: A URI must not start nor end with ASCII…
- Invalid URI: Scheme is malformed.
- Invalid URI.
AI-assisted analysis of symfony/http-foundation@5aea19cd67 (2026-09-13).
Data as JSON: /api/errors/92eb37115013c2aa.
Report an issue: GitHub.
Appendix: source
Thrown at Request.php:406
], $server);
$server['PATH_INFO'] = '';
$server['REQUEST_METHOD'] = strtoupper($method);
if (($i = strcspn($uri, ':/?#')) && ':' === ($uri[$i] ?? null) && (strspn($uri, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-.') !== $i || strcspn($uri, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'))) {
throw new BadRequestException('Invalid URI: Scheme is malformed.');
}
if (false === $components = parse_url(\strlen($uri) !== strcspn($uri, '?#') ? $uri : $uri.'#')) {
throw new BadRequestException('Invalid URI.');
}
$part = ($components['user'] ?? '').':'.($components['pass'] ?? '');
if (':' !== $part && \strlen($part) !== strcspn($part, '[]')) {
throw new BadRequestException('Invalid URI: Userinfo is malformed.');
}
if (($part = $components['host'] ?? '') && !self::isHostValid($part)) {
throw new BadRequestException('Invalid URI: Host is malformed.');
}
if (false !== ($i = strpos($uri, '\\')) && $i < strcspn($uri, '?#')) {
throw new BadRequestException('Invalid URI: A URI cannot contain a backslash.');
}
if (\strlen($uri) !== strcspn($uri, "\r\n\t")) {
throw new BadRequestException('Invalid URI: A URI cannot contain CR/LF/TAB characters.');
}
if ('' !== $uri && (\ord($uri[0]) <= 32 || \ord($uri[-1]) <= 32)) {
throw new BadRequestException('Invalid URI: A URI must not start nor end with ASCII control characters or spaces.');
}
if (isset($components['host'])) {
$server['SERVER_NAME'] = $components['host'];
$server['HTTP_HOST'] = $components['host'];
}
if (isset($components['scheme'])) {
if ('https' === $components['scheme']) {View on GitHub (pinned to 5aea19cd67)