ginuerzh/gost · error

bind: read reply %v

Error message

bind: read reply %v

What it means

This error is returned by the SOCKS5 BIND client (socks5BindConn) when gosocks5.ReadReply fails while waiting for the server's second BIND reply (the reply sent when the peer finally connects back to the server's bind port). The wrapped %v is the underlying read/parse/transport error, so the message shows why the reply could not be read (connection reset, EOF, timeout, malformed reply).

Source

Thrown at socks.go:1998

	net.Conn
	handshaked   bool
	handshakeMux sync.Mutex
}

// Handshake waits for a peer to connect to the bind port.
func (c *socks5BindConn) Handshake() (err error) {
	c.handshakeMux.Lock()
	defer c.handshakeMux.Unlock()

	if c.handshaked {
		return nil
	}

	c.handshaked = true

	rep, err := gosocks5.ReadReply(c.Conn)
	if err != nil {
		return fmt.Errorf("bind: read reply %v", err)
	}
	if rep.Rep != gosocks5.Succeeded {
		return fmt.Errorf("bind: peer connect failure")
	}
	c.raddr, err = net.ResolveTCPAddr("tcp", rep.Addr.String())
	return
}

func (c *socks5BindConn) Read(b []byte) (n int, err error) {
	if err = c.Handshake(); err != nil {
		return
	}
	return c.Conn.Read(b)
}

func (c *socks5BindConn) Write(b []byte) (n int, err error) {
	if err = c.Handshake(); err != nil {
		return

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Inspect the wrapped error (%v) to identify the root cause (EOF, reset, timeout) and check proxy server logs
  2. Verify network paths (NAT, firewalls) keep the control connection alive long enough for the peer to connect back
  3. Increase client timeout / keepalive settings if applicable
  4. Retry the BIND operation, or switch to CONNECT-based proxying if reverse connections are not required

Example fix

// before
rep, err := gosocks5.ReadReply(c.Conn)
if err != nil {
    return fmt.Errorf("bind: read reply %v", err)
}
// after: surface the underlying cause distinctly
rep, err := gosocks5.ReadReply(c.Conn)
if err != nil {
    return fmt.Errorf("bind: read reply: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// before BIND, verify proxy reachability
conn, err := net.DialTimeout("tcp", proxyAddr, 5*time.Second)
if err != nil { return fmt.Errorf("proxy unreachable: %w", err) }

Try / catch

for attempt := 0; attempt < 3; attempt++ {
    c, err := dialer.Bind(ctx, addr)
    if err != nil {
        if strings.Contains(err.Error(), "bind: read reply") { time.Sleep(backoff); continue }
        return err
    }
    break
}

Prevention

When it happens

Trigger: Calling Connect on a SOCKS5 BIND dialer and the control connection drops or times out while blocked waiting for gosocks5.ReadReply to return the second reply (after the first reply confirmed the bind address).

Common situations: The remote peer never connects back within the proxy's timeout; a NAT/firewall kills the idle control connection; the proxy server crashes or closes the connection mid-BIND handshake.

Related errors


AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02). Data as JSON: /api/errors/5388eb288dd2b379. Report an issue: GitHub.