{"record":{"id":"fa67b464f2b2cff1","repo":"nats-io/nats-server","slug":"proxy-url-must-specify-a-host","errorCode":null,"errorMessage":"proxy URL must specify a host","messagePattern":"proxy URL must specify a host","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/leafnode.go","lineNumber":408,"sourceCode":"\nfunc validateLeafNodeProxyOptions(remote *RemoteLeafOpts) ([]string, error) {\n\tvar warnings []string\n\n\tif remote.Proxy.URL == _EMPTY_ {\n\t\treturn warnings, nil\n\t}\n\n\tproxyURL, err := url.Parse(remote.Proxy.URL)\n\tif err != nil {\n\t\treturn warnings, fmt.Errorf(\"invalid proxy URL: %v\", err)\n\t}\n\n\tif proxyURL.Scheme != \"http\" && proxyURL.Scheme != \"https\" {\n\t\treturn warnings, fmt.Errorf(\"proxy URL scheme must be http or https, got: %s\", proxyURL.Scheme)\n\t}\n\n\tif proxyURL.Host == _EMPTY_ {\n\t\treturn warnings, fmt.Errorf(\"proxy URL must specify a host\")\n\t}\n\n\tif remote.Proxy.Timeout < 0 {\n\t\treturn warnings, fmt.Errorf(\"proxy timeout must be >= 0\")\n\t}\n\n\tif (remote.Proxy.Username == _EMPTY_) != (remote.Proxy.Password == _EMPTY_) {\n\t\treturn warnings, fmt.Errorf(\"proxy username and password must both be specified or both be empty\")\n\t}\n\n\tif len(remote.URLs) > 0 {\n\t\thasWebSocketURL := false\n\t\thasNonWebSocketURL := false\n\n\t\tfor _, remoteURL := range remote.URLs {\n\t\t\tif remoteURL.Scheme == wsSchemePrefix || remoteURL.Scheme == wsSchemePrefixTLS {\n\t\t\t\thasWebSocketURL = true\n\t\t\t\tif (remoteURL.Scheme == wsSchemePrefixTLS) &&","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/leafnode.go#L390-L426","documentation":"NATS server rejects a leafnode remote proxy URL that has no host component. When a proxy is configured via remote.Proxy.URL, the URL must point at an actual proxy host; a scheme-only URL like 'http://' carries no routing information and cannot be dialed. validateLeafNodeProxyOptions fails fast at config parse time so the server never starts with an unusable proxy.","triggerScenarios":"Setting a leafnode remote proxy URL to a value without a host, e.g. proxy_url: \"http://\" or \"https://\" in the leafnodes remotes config, or constructing url.URL{Scheme: \"http\"} with empty Host in code before parseRemoteLeafNodes/validateLeafNode runs.","commonSituations":"Config templating that leaves the proxy host variable empty (unset env var interpolated to nothing); hand-edited nats.conf dropping the host after the scheme; copy-paste of a proxy option block without filling in the address.","solutions":["Set a full proxy URL including host and port, e.g. proxy_url: \"http://proxy.internal:3128\"","Check that any env-expanded variable in the proxy URL is non-empty before starting the server","Validate the URL with url.Parse and check u.Host != \"\" in your deployment tooling"],"exampleFix":"// before\nproxy_url: \"http://\"\n// after\nproxy_url: \"http://proxy.internal:3128\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(proxyURLString)\nif err != nil || u.Scheme != \"http\" && u.Scheme != \"https\" || u.Host == \"\" {\n    return fmt.Errorf(\"proxy URL must be http(s) with a host, got %q\", proxyURLString)\n}","typeGuard":"func hasProxyHost(raw string) bool {\n    u, err := url.Parse(raw)\n    return err == nil && u.Host != \"\"\n}","tryCatchPattern":"if err := server.CheckLeafNodeProxy(cfg); err != nil {\n    log.Fatalf(\"invalid proxy config: %v\", err)\n}","preventionTips":["Always include host:port in proxy_url","Lint nats.conf for empty interpolated variables before deploy","Validate config with nats-server --config ... -t (config test) before restart"],"tags":["configuration","leafnode","proxy","url"],"backgroundTag":"invalid-url","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}