nats-io/nats-server · error

proxy timeout must be >= 0

Error message

proxy timeout must be >= 0

What it means

The leafnode remote proxy timeout is negative. validateLeafNodeProxyOptions enforces remote.Proxy.Timeout >= 0 because a negative dial/handshake timeout is meaningless and would be rejected or misbehave downstream in natsDialTimeout. This is a config-time validation error.

Source

Thrown at server/leafnode.go:412

	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) &&
					remote.TLSConfig == nil && !remote.TLS {
					return warnings, fmt.Errorf("proxy is configured but remote URL %s requires TLS and no TLS configuration is provided. When using proxy with TLS endpoints, ensure TLS is properly configured for the leafnode remote", remoteURL.String())
				}
			} else {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Set the proxy timeout to a non-negative duration, e.g. timeout: "5s" or omit it to use the default
  2. Audit config for leading minus signs on duration fields
  3. Clamp computed durations with a max(0, d) before assigning remote.Proxy.Timeout

Example fix

// before
proxy {
  url: "http://proxy:3128"
  timeout: -5s
}
// after
proxy {
  url: "http://proxy:3128"
  timeout: 5s
}
Defensive patterns

Strategy: validation

Validate before calling

if cfg.Proxy != nil && cfg.Proxy.Timeout < 0 {
    return fmt.Errorf("proxy timeout must be >= 0, got %v", cfg.Proxy.Timeout)
}

Type guard

func validProxyTimeout(d time.Duration) bool { return d >= 0 }

Try / catch

defer func() {
    if r := recover(); r != nil { log.Fatalf("leafnode config rejected: %v", r) }
}()
// or: check the error from option parsing before starting the server

Prevention

When it happens

Trigger: Configuring proxy { timeout: -1 } (or any negative value) under a leafnode remote; parsing a duration that resolves negative, e.g. timeout: "-5s" or a computed negative time.Duration passed programmatically to parseRemoteLeafNodes.

Common situations: Sign typo in config (-5s instead of 5s); arithmetic on durations producing negatives; templates substituting negative defaults.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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