nats-io/nats-server · error

failed to set deadline: %v

Error message

failed to set deadline: %v

What it means

Setting the handshake deadline on the freshly opened proxy connection failed. The code calls conn.SetDeadline(time.Now().Add(timeout)) to bound the entire CONNECT exchange; a non-nil error (e.g. the conn is already closed or the underlying transport does not support deadlines) aborts the tunnel. This is rare and usually indicates a broken/aborted connection immediately after dial.

Source

Thrown at server/leafnode.go:638

// 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,
		Header: make(http.Header),
	}

	// Add proxy authentication if provided
	if username != "" && password != "" {
		req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(username+":"+password)))
	}

	if err := req.Write(conn); err != nil {
		conn.Close()
		return nil, fmt.Errorf("failed to write CONNECT request: %v", err)
	}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Retry the connection — the socket was likely reset by the peer
  2. Inspect why the proxy/LB drops connections right after accept
  3. In tests, use deadline-capable pipes (net.Pipe wrapped) or a real listener
Defensive patterns

Strategy: retry

Try / catch

conn, err := establishHTTPProxyTunnel(purl, target, timeout, user, pass)
if err != nil {
    if strings.Contains(err.Error(), "failed to set deadline") {
        time.Sleep(backoff)
        conn, err = establishHTTPProxyTunnel(purl, target, timeout, user, pass)
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: conn.SetDeadline returning an error right after natsDialTimeout succeeded — connection reset/closed between dial and deadline set, or a custom net.Conn implementation without deadline support injected in tests.

Common situations: Proxy closing the socket instantly (port opened then dropped by an LB or tcpwrap); test doubles using pipe connections without deadline support; kernel-level connection aborts under load.

Related errors


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