ginuerzh/gost · error
peer connect failure
Error message
peer connect failure
What it means
waitConnectSOCKS5 returns 'peer connect failure' when the remote SOCKS5 relay answered the CONNECT for the peer (client behind NAT) with a non-Succeeded reply code. The remote relay reached the relay, but the relay could not establish the connection to the peer endpoint (rep.Rep carries the SOCKS5 failure reason).
Source
Thrown at forward.go:578
log.Log("[rtcp] SOCKS5 BIND reply: ", err)
return nil, err
}
conn.SetReadDeadline(time.Time{})
if rep.Rep != gosocks5.Succeeded {
log.Logf("[rtcp] bind on %s failure", l.addr)
return nil, fmt.Errorf("Bind on %s failure", l.addr.String())
}
log.Logf("[rtcp] BIND ON %s OK", rep.Addr)
// second reply, peer connected
rep, err = gosocks5.ReadReply(conn)
if err != nil {
log.Log("[rtcp]", err)
return nil, err
}
if rep.Rep != gosocks5.Succeeded {
log.Logf("[rtcp] peer connect failure: %d", rep.Rep)
return nil, errors.New("peer connect failure")
}
log.Logf("[rtcp] PEER %s CONNECTED", rep.Addr)
return conn, nil
}
func (l *tcpRemoteForwardListener) Addr() net.Addr {
if l.ln != nil {
return l.ln.Addr()
}
return l.addr
}
func (l *tcpRemoteForwardListener) Close() error {
if l.ln != nil {
return l.ln.Close()
}
View on GitHub (pinned to a33fdbf4c9)
Solutions
- Check the remote log line '[rtcp] peer connect failure: <code>' for the exact SOCKS5 reply code
- Verify the peer (client behind NAT) is running and listening on the expected port
- Fix firewall/NAT rules on the peer side allowing the relay's inbound connection
- Confirm remote relay node connectivity and that its egress permits reaching the peer
Example fix
// before
conn, err := l.waitConnectSOCKS5(...) // opaque failure
// after
conn, err := l.waitConnectSOCKS5(...)
if err != nil {
if err.Error() == "peer connect failure" {
// inspect remote logs for rep.Rep; retry after peer is reachable
return nil, fmt.Errorf("peer connect failure (rep=%d): retry after peer reachable", lastRep)
}
return nil, err
} Defensive patterns
Strategy: retry
Validate before calling
// before accepting a rtcp tunnel, verify peer reachability
conn, err := net.DialTimeout("tcp", peerAddr, 5*time.Second)
if err != nil {
return fmt.Errorf("peer %s not reachable before tunnel setup: %w", peerAddr, err)
} Type guard
func isPeerConnectFailure(err error) bool {
return err != nil && err.Error() == "peer connect failure"
} Try / catch
conn, err := l.Accept()
if err != nil {
if isPeerConnectFailure(err) {
// inspect remote 'peer connect failure: <rep>' log, wait, then retry
time.Sleep(backoff)
return retry()
}
return err
} Prevention
- Health-check the peer endpoint before registering the remote forward
- Read the SOCKS5 reply code in remote logs to distinguish refused vs unreachable vs forbidden
- Keep peers listening and reachable through their NAT (keepalive/heartbeat)
- Configure retries with backoff instead of treating a single failure as fatal
When it happens
Trigger: Accepting a remote port-forward (rtcp) where the remote server's SOCKS5 CONNECT reply rep.Rep != gosocks5.Succeeded — e.g. host unreachable, connection refused, or not allowed on the remote side.
Common situations: NAT hole-punching for reverse tunnels where the client-side peer is down, firewall blocks the remote relay to peer hop, wrong peer port in rtcp config, remote relay lacks outbound access.
Related errors
AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02).
Data as JSON: /api/errors/37d341f828f81149.
Report an issue: GitHub.