{"record":{"id":"e6d26dd0c92a8821","repo":"cloudflare/cloudflared","slug":"hostname-actually-a-url-s-has-invalid-escape-cha","errorCode":null,"errorMessage":"Hostname(actually a URL) %s has invalid escape characters %s","messagePattern":"Hostname\\(actually a URL\\) (.+?) has invalid escape characters (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"validation/validation.go","lineNumber":37,"sourceCode":"\taccessDomain    = \"cloudflareaccess.com\"\n\taccessCertPath  = \"/cdn-cgi/access/certs\"\n\taccessJwtHeader = \"Cf-access-jwt-assertion\"\n)\n\nvar (\n\tsupportedProtocols = []string{\"http\", \"https\", \"rdp\", \"ssh\", \"smb\", \"tcp\"}\n\tvalidationTimeout  = time.Duration(30 * time.Second)\n)\n\nfunc ValidateHostname(hostname string) (string, error) {\n\tif hostname == \"\" {\n\t\treturn \"\", nil\n\t}\n\t// users gives url(contains schema) not just hostname\n\tif strings.Contains(hostname, \":\") || strings.Contains(hostname, \"%3A\") {\n\t\tunescapeHostname, err := url.PathUnescape(hostname)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"Hostname(actually a URL) %s has invalid escape characters %s\", hostname, unescapeHostname)\n\t\t}\n\t\thostnameToURL, err := url.Parse(unescapeHostname)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"Hostname(actually a URL) %s has invalid format %s\", hostname, hostnameToURL)\n\t\t}\n\t\tasciiHostname, err := idna.ToASCII(hostnameToURL.Hostname())\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"Hostname(actually a URL) %s has invalid ASCII encdoing %s\", hostname, asciiHostname)\n\t\t}\n\t\treturn asciiHostname, nil\n\t}\n\n\tasciiHostname, err := idna.ToASCII(hostname)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"Hostname %s has invalid ASCII encdoing %s\", hostname, asciiHostname)\n\t}\n\thostnameToURL, err := url.Parse(asciiHostname)\n\tif err != nil {","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/validation/validation.go#L19-L55","documentation":"When ValidateHostname receives a value containing ':' or '%3A' it treats it as a URL rather than a bare hostname and attempts url.PathUnescape. This error fires when the percent-encoding is malformed (invalid escape sequences), so the input cannot be unescaped into a parseable URL.","triggerScenarios":"Calling ValidateHostname with a string containing ':' or '%3A' that url.PathUnescape fails on, e.g. \"example.com%3\" (truncated percent-escape) or stray '%' characters in a tunnel hostname/URL argument.","commonSituations":"Users passing a full URL (with port/scheme) where cloudflared expects only a hostname, with hand-mangled percent-encoding; copy-pasted URLs from logs or HTML where '%' got corrupted.","solutions":["Pass a plain hostname (e.g. example.com) without ports, schemes, or percent-encoding","If a URL is needed, pass a well-formed one: https://example.com:8080 — ensure % sequences are valid percent-escapes","Decode the value yourself correctly before passing it in","Check for stray '%' characters introduced by copy-paste and remove or fix them"],"exampleFix":"// before\nhostname, err := validation.ValidateHostname(\"example.com%3A\")\n// after\nhostname, err := validation.ValidateHostname(\"example.com\")","handlingStrategy":"validation","validationCode":"func validHostOrURL(s string) bool {\n    if s == \"\" { return false }\n    if strings.Contains(s, \":\") || strings.Contains(s, \"%3A\") {\n        unesc, err := url.PathUnescape(s)\n        if err != nil { return false }\n        _, err = url.Parse(unesc)\n        return err == nil\n    }\n    return true\n}","typeGuard":null,"tryCatchPattern":"host, err := validation.ValidateHostname(input)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid escape characters\") {\n        return fmt.Errorf(\"hostname %q contains malformed percent-encoding; pass a plain hostname\", input)\n    }\n    return err\n}","preventionTips":["Pass bare hostnames, not URLs, where a hostname is expected","Avoid manual percent-encoding of hostnames","Pre-sanitize inputs copied from logs/HTML that may contain stray '%'"],"tags":["hostname","validation","url","percent-encoding"],"backgroundTag":"invalid-url-format","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}