nats-io/nats-server · error

unexpected proxy URL parse error (URL was pre-validated): %v

Error message

unexpected proxy URL parse error (URL was pre-validated): %v

What it means

establishHTTPProxyTunnel failed to re-parse the proxy URL string that was already validated during configuration. This is a defensive/unexpected path — by the time the tunnel is established the URL passed validation, so url.Parse should never fail. Hitting it indicates an internal inconsistency (URL mutated between validation and dial) rather than a user config problem.

Source

Thrown at server/leafnode.go:626

	}
	s.leafNodeOpts.resolver = opts.LeafNode.resolver
	if s.leafNodeOpts.resolver == nil {
		s.leafNodeOpts.resolver = net.DefaultResolver
	}
	s.leafNodeOpts.dialer = opts.LeafNode.dialer
	if s.leafNodeOpts.dialer == nil {
		s.leafNodeOpts.dialer = natsDialTimeout
	}
}

const sharedSysAccDelay = 250 * time.Millisecond

// establishHTTPProxyTunnel establishes an HTTP CONNECT tunnel through a proxy server
func establishHTTPProxyTunnel(proxyURL, targetHost string, timeout time.Duration, username, password string) (net.Conn, error) {
	proxyAddr, err := url.Parse(proxyURL)
	if err != nil {
		// This should not happen since proxy URL is validated during configuration parsing
		return nil, fmt.Errorf("unexpected proxy URL parse error (URL was pre-validated): %v", err)
	}

	// Connect to the proxy server
	conn, err := natsDialTimeout("tcp", proxyAddr.Host, timeout)
	if err != nil {
		return nil, fmt.Errorf("failed to connect to proxy: %v", err)
	}

	// Set deadline for the entire proxy handshake
	if err := conn.SetDeadline(time.Now().Add(timeout)); err != nil {
		conn.Close()
		return nil, fmt.Errorf("failed to set deadline: %v", err)
	}

	req := &http.Request{
		Method: http.MethodConnect,
		URL:    &url.URL{Opaque: targetHost}, // Opaque is required for CONNECT
		Host:   targetHost,

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Check whether any code mutates the remote's Proxy URL after validation
  2. Call establishHTTPProxyTunnel only with URLs that passed validateLeafNodeProxyOptions
  3. If reproducible with stock config, report as a bug with the exact proxy URL value
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := url.Parse(proxyURL); err != nil {
    return fmt.Errorf("proxy URL invalid before tunnel: %w", err)
}

Type guard

func parseableProxyURL(raw string) bool {
    _, err := url.Parse(raw)
    return err == nil
}

Try / catch

conn, err := establishHTTPProxyTunnel(purl, host, timeout, user, pass)
if err != nil {
    if strings.Contains(err.Error(), "unexpected proxy URL parse error") {
        log.Fatalf("BUG: proxy URL mutated after validation: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: url.Parse(proxyURL) returning an error inside establishHTTPProxyTunnel despite pre-validation in validateLeafNodeProxyOptions — practically only if the stored proxy URL string is corrupt or modified after parsing.

Common situations: Bugs in code that rewrites the proxy URL between config validation and connection; custom test harnesses calling establishHTTPProxyTunnel with an unvalidated string.

Understand the failure class

Related errors


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