nats-io/nats-server · error

proxy URL must specify a host

Error message

proxy URL must specify a host

What it means

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.

Source

Thrown at server/leafnode.go:408

func validateLeafNodeProxyOptions(remote *RemoteLeafOpts) ([]string, error) {
	var warnings []string

	if remote.Proxy.URL == _EMPTY_ {
		return warnings, nil
	}

	proxyURL, err := url.Parse(remote.Proxy.URL)
	if err != nil {
		return warnings, fmt.Errorf("invalid proxy URL: %v", err)
	}

	if proxyURL.Scheme != "http" && proxyURL.Scheme != "https" {
		return warnings, fmt.Errorf("proxy URL scheme must be http or https, got: %s", proxyURL.Scheme)
	}

	if proxyURL.Host == _EMPTY_ {
		return warnings, fmt.Errorf("proxy URL must specify a host")
	}

	if remote.Proxy.Timeout < 0 {
		return warnings, fmt.Errorf("proxy timeout must be >= 0")
	}

	if (remote.Proxy.Username == _EMPTY_) != (remote.Proxy.Password == _EMPTY_) {
		return warnings, fmt.Errorf("proxy username and password must both be specified or both be empty")
	}

	if len(remote.URLs) > 0 {
		hasWebSocketURL := false
		hasNonWebSocketURL := false

		for _, remoteURL := range remote.URLs {
			if remoteURL.Scheme == wsSchemePrefix || remoteURL.Scheme == wsSchemePrefixTLS {
				hasWebSocketURL = true
				if (remoteURL.Scheme == wsSchemePrefixTLS) &&

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Set a full proxy URL including host and port, e.g. proxy_url: "http://proxy.internal:3128"
  2. Check that any env-expanded variable in the proxy URL is non-empty before starting the server
  3. Validate the URL with url.Parse and check u.Host != "" in your deployment tooling

Example fix

// before
proxy_url: "http://"
// after
proxy_url: "http://proxy.internal:3128"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(proxyURLString)
if err != nil || u.Scheme != "http" && u.Scheme != "https" || u.Host == "" {
    return fmt.Errorf("proxy URL must be http(s) with a host, got %q", proxyURLString)
}

Type guard

func hasProxyHost(raw string) bool {
    u, err := url.Parse(raw)
    return err == nil && u.Host != ""
}

Try / catch

if err := server.CheckLeafNodeProxy(cfg); err != nil {
    log.Fatalf("invalid proxy config: %v", err)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/fa67b464f2b2cff1. Report an issue: GitHub.