{"record":{"id":"ae19bdd642015e20","repo":"valyala/fasthttp","slug":"invalid-host-q-with-multiple-port-delimiters","errorCode":null,"errorMessage":"invalid host %q with multiple port delimiters","messagePattern":"invalid host %q with multiple port delimiters","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"uri.go","lineNumber":473,"sourceCode":"\t\t\t}\n\t\t\thost2, err := unescape(host[zone:i], encodeZone)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\thost3, err := unescape(host[i:], encodeHost)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn append(host1, append(host2, host3...)...), nil\n\t\t}\n\t} else {\n\t\tif bytes.IndexByte(host, '[') >= 0 || bytes.IndexByte(host, ']') >= 0 {\n\t\t\treturn nil, fmt.Errorf(\"invalid host %q\", host)\n\t\t}\n\n\t\tif i := bytes.LastIndexByte(host, ':'); i != -1 {\n\t\t\tif bytes.IndexByte(host[:i], ':') != -1 {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid host %q with multiple port delimiters\", host)\n\t\t\t}\n\n\t\t\tcolonPort := host[i:]\n\t\t\tif !validOptionalPort(colonPort) {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid port %q after host\", colonPort)\n\t\t\t}\n\t\t}\n\t}\n\n\tvar err error\n\tif host, err = unescape(host, encodeHost); err != nil {\n\t\treturn nil, err\n\t}\n\tif err = validateIPv6Literal(host); err != nil {\n\t\treturn nil, err\n\t}\n\treturn host, nil\n}","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/uri.go#L455-L491","documentation":"url.Parse's parseHost validates the host portion of an authority. After locating the last ':' (candidate port delimiter), it rejects the host if another ':' appears before it. Bracketed IPv6 hosts are handled earlier, so any remaining multi-colon host is invalid.","triggerScenarios":"Parsing a URL whose host contains two or more colons outside brackets, e.g. http.Parse(\"http://host:8080:90/\") or \"http://::1/\" (unbracketed IPv6 literal).","commonSituations":"IPv6 addresses pasted without [ ] brackets; concatenating host and port strings twice (host+\":\"+port where host already has a port); proxy strings like host:port accidentally used as a URL host.","solutions":["Wrap IPv6 literals in square brackets: http://[::1]:8080/","Remove the duplicate port delimiter; pass only host:port once","If input comes from config, split and validate host/port separately before building the URL"],"exampleFix":"// before\nu, err := url.Parse(\"http://::1:8080/path\")\n// after\nu, err := url.Parse(\"http://[::1]:8080/path\")","handlingStrategy":"validation","validationCode":"func validURLHost(raw string) bool {\n    u, err := url.Parse(raw)\n    return err == nil && u.Host != \"\"\n}\n// call before using the URL in the API","typeGuard":"func isBracketedIPv6(host string) bool {\n    return strings.HasPrefix(host, \"[\") && strings.Contains(host, \"]\")\n}","tryCatchPattern":"u, err := url.Parse(rawURL)\nif err != nil {\n    var ue *url.Error\n    if errors.As(err, &ue) && strings.Contains(ue.Err.Error(), \"invalid host\") {\n        // normalize: bracket IPv6 or strip extra ':'\n    }\n    return fmt.Errorf(\"bad URL host in %q: %w\", rawURL, err)\n}","preventionTips":["Always bracket IPv6 literals in URLs","Build URLs with url.URL{Host: ...} instead of string concatenation","Never append a port to a value that may already contain ':'"],"tags":["url-parsing","net-url","host-validation"],"backgroundTag":"invalid-url-host","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}