{"record":{"id":"326af5a3563a6c3b","repo":"cloudflare/cloudflared","slug":"url-no-s-has-invalid-format","errorCode":null,"errorMessage":"URL no %s has invalid format","messagePattern":"URL no (.+?) has invalid format","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"validation/validation.go","lineNumber":133,"sourceCode":"\t\t}\n\t\t// The earlier check for ip address will miss the case http://[::1]\n\t\t// and http://[::1]:8080\n\t\tif net.ParseIP(parsedUrl.Hostname()) != nil {\n\t\t\treturn validateIP(parsedUrl.Scheme, parsedUrl.Hostname(), parsedUrl.Port())\n\t\t}\n\t\thostname, err = ValidateHostname(parsedUrl.Hostname())\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"URL %s has invalid format\", originUrl)\n\t\t}\n\t\tif parsedUrl.Port() != \"\" {\n\t\t\treturn fmt.Sprintf(\"%s://%s\", parsedUrl.Scheme, net.JoinHostPort(hostname, parsedUrl.Port())), nil\n\t\t}\n\t\treturn fmt.Sprintf(\"%s://%s\", parsedUrl.Scheme, hostname), nil\n\t} else {\n\t\tif host == \"\" {\n\t\t\thostname, err = ValidateHostname(originUrl)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"URL no %s has invalid format\", originUrl)\n\t\t\t}\n\t\t\treturn fmt.Sprintf(\"%s://%s\", defaultScheme, hostname), nil\n\t\t} else {\n\t\t\thostname, err = ValidateHostname(host)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"URL %s has invalid format\", originUrl)\n\t\t\t}\n\t\t\t// This is why the path is preserved when `originUrl` doesn't have a schema.\n\t\t\t// Using `parsedUrl.Port()` here, instead of `port`, would remove the path\n\t\t\treturn fmt.Sprintf(\"%s://%s\", defaultScheme, net.JoinHostPort(hostname, port)), nil\n\t\t}\n\t}\n\n}\n\nfunc validateScheme(scheme string) error {\n\tfor _, protocol := range supportedProtocols {\n\t\tif scheme == protocol {","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/validation/validation.go#L115-L151","documentation":"In the no-scheme branch, when net.SplitHostPort left host empty (input had no scheme and wasn't host:port-IP), the whole originUrl is validated as a hostname. If ValidateHostname fails, this error (note the odd 'URL no %s' wording, a typo for the URL without scheme) is returned.","triggerScenarios":"ValidateUrl('bad_host!') or any scheme-less input whose hostname fails ValidateHostname: invalid IDNA characters, strings containing ':' that don't unescape/parse (e.g. 'localhost:port' with a non-numeric port reaching the hostname path).","commonSituations":"Typo'd hostnames in ingress config, scheme-less values like 'my_service:2000' where SplitHostPort succeeded (host='my_service' actually — this branch hits when host==''), or unicode hostnames in config files.","solutions":["Check the scheme-less value is a valid hostname (letters, digits, hyphens, dots) or host:port","Add an explicit scheme (http:// or ssh://) so the URL branch is taken instead of the hostname branch","Run idna.ToASCII on the value directly to see the real validation failure hidden by this wrapper","Fix typos or invalid characters in the config value"],"exampleFix":"// before\nValidateUrl(\"my_host:abc\") // URL no my_host:abc has invalid format\n// after\nValidateUrl(\"tcp://my_host:2000\") // explicit supported scheme","handlingStrategy":"validation","validationCode":"func validOrigin(s string) bool {\n    if strings.Contains(s, \":\") { return true } // has scheme or port\n    _, err := idna.ToASCII(s)\n    return err == nil && s != \"\"\n}","typeGuard":null,"tryCatchPattern":"u, err := validation.ValidateUrl(origin)\nif err != nil {\n    return fmt.Errorf(\"hostname %q failed validation: %w\", origin, err)\n}","preventionTips":["Always include an explicit supported scheme in origin config","Verify scheme-less values are plain DNS hostnames","Run idna.ToASCII on the value during config load for early feedback"],"tags":["url","validation","hostname","configuration"],"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"}