{"record":{"id":"4632641822dc8047","repo":"getgrav/grav","slug":"uri-host-name-validation-failed","errorCode":null,"errorMessage":"Uri host name validation failed","messagePattern":"Uri host name validation failed","errorType":"validation","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/Uri/UriPartsFilter.php","lineNumber":72,"sourceCode":"            $info\n        ) ?? '';\n    }\n\n    /**\n     * @param string $host\n     * @return string\n     * @throws InvalidArgumentException If the host is invalid.\n     */\n    public static function filterHost($host)\n    {\n        if (!is_string($host)) {\n            throw new InvalidArgumentException('Uri host must be a string');\n        }\n\n        if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {\n            $host = '[' . $host . ']';\n        } elseif ($host && preg_match(static::HOSTNAME_REGEX, $host) !== 1) {\n            throw new InvalidArgumentException('Uri host name validation failed');\n        }\n\n        return strtolower($host);\n    }\n\n    /**\n     * Filter Uri port.\n     *\n     * This method\n     *\n     * @param int|null $port\n     * @return int|null\n     * @throws InvalidArgumentException If the port is invalid.\n     */\n    public static function filterPort($port = null)\n    {\n        if (null === $port || (is_int($port) && ($port >= 0 && $port <= 65535))) {\n            return $port;","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/Uri/UriPartsFilter.php#L54-L90","documentation":"After the is_string check, filterHost() validates the value: a bare IPv6 address gets bracketed, but any other non-empty host must match HOSTNAME_REGEX (labels of alphanumerics/hyphens joined by dots) or InvalidArgumentException 'Uri host name validation failed' is thrown. Notably the regex rejects underscores, empty labels (double dots, leading/trailing dot), and labels starting/ending with a hyphen. IPv4 passes because numeric labels satisfy the pattern.","triggerScenarios":"Hostnames containing underscores (`my_site.local`, Docker aliases like `my_app_1`); a host with a trailing dot (`example.com.`); passing `host:port` together so the colon fails the regex; labels with leading/trailing hyphens; hosts built from unvalidated header input containing spaces or slashes.","commonSituations":"Internal/dev hostnames with underscores (technically invalid per RFC but common in DNS and Docker); misconfigured SERVER_NAME/HTTP_HOST; proxies forwarding a malformed Host header; code passing an unsplit 'example.com:8080' into withHost().","solutions":["Replace underscores with hyphens in the hostname (underscores are invalid in RFC hostnames)","Split off the port before filtering: `[$host, $port] = explode(':', $host . ':')` and pass the port to withPort()","Strip a trailing dot and re-check labels if you accept FQDNs from DNS output","Validate/sanitize Host-derived input from headers before building Uris"],"exampleFix":"// before\n$uri = $uri->withHost('my_site.local:8080'); // underscore + port -> validation failed\n\n// after\n$host = str_replace('_', '-', 'my_site.local');\n$uri = $uri->withHost($host)->withPort(8080);","handlingStrategy":"validation","validationCode":"function isAcceptableHost(string $host): bool\n{\n    $host = rtrim($host, '.'); // tolerate FQDN trailing dot\n    return $host === ''\n        || (bool) filter_var($host, FILTER_VALIDATE_IP)\n        || preg_match('/^(?=.{1,253}$)([a-z0-9]([a-z0-9-]*[a-z0-9])?\\.)*[a-z0-9]([a-z0-9-]*[a-z0-9])?$/i', $host) === 1;\n}","typeGuard":null,"tryCatchPattern":"try {\n    $uri = $uri->withHost($host);\n} catch (\\InvalidArgumentException $e) {\n    // 'Uri host name validation failed' — sanitize or reject the host\n    $uri = $uri->withHost('localhost'); // or throw 400 for user-supplied hosts\n}","preventionTips":["Reject underscores in hostnames at the config/DNS level — use hyphens","Split 'host:port' before calling withHost(); pass the port to withPort()","Validate Host/X-Forwarded-Host header values against a hostname pattern before building URIs","Strip trailing dots from DNS-derived FQDNs"],"tags":["uri","host","hostname","validation","rfc-3986"],"backgroundTag":"invalid-hostname","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}