snail007/goproxy · error
write connection data err: %s ,retrying...
Error message
write connection data err: %s ,retrying...
What it means
After GetConn succeeds, GetInConn writes a handshake packet (type, key length, key) to the new connection. This error is thrown when that write fails; the connection is closed immediately so the caller can retry, as the message says.
Source
Thrown at services/tunnel_client.go:94
}
func (s *TunnelClient) Clean() {
s.StopService()
}
func (s *TunnelClient) GetInConn(typ uint8) (outConn net.Conn, err error) {
outConn, err = s.GetConn()
if err != nil {
err = fmt.Errorf("connection err: %s", err)
return
}
keyBytes := []byte(*s.cfg.Key)
keyLength := uint16(len(keyBytes))
pkg := new(bytes.Buffer)
binary.Write(pkg, binary.LittleEndian, typ)
binary.Write(pkg, binary.LittleEndian, keyLength)
binary.Write(pkg, binary.LittleEndian, keyBytes)
_, err = outConn.Write(pkg.Bytes())
if err != nil {
err = fmt.Errorf("write connection data err: %s ,retrying...", err)
utils.CloseConn(&outConn)
return
}
return
}
func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
var _conn tls.Conn
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
if err == nil {
conn = net.Conn(&_conn)
}
return
}
func (s *TunnelClient) ServeUDP() {
var inConn net.Conn
var err error
for {
for {View on GitHub (pinned to e6d6a821db)
Solutions
- Confirm the client key (cfg.Key) matches the server's key, since the server may drop conns on bad keys
- Retry the operation — the code already closes the conn and the message indicates retrying; add backoff in your wrapper
- Check server-side logs at the same timestamp for why the server closed the accepted connection
- Stabilize the network path (keep-alives, TCP keepalive settings) if running over flaky links
Example fix
// before: fire-and-forget single attempt
conn, err := client.GetInConn(typ)
// after: retry with backoff
var conn net.Conn
for i := 0; i < 3; i++ {
conn, err = client.GetInConn(typ)
if err == nil { break }
time.Sleep(time.Duration(1<<i) * time.Second)
} Defensive patterns
Strategy: retry
Validate before calling
// verify key length is sane and matches server expectation before writing
if len(cfg.Key) == 0 || len(cfg.Key) > 65535 {
return errors.New("tunnel key must be non-empty and <64KB")
} Try / catch
conn, err := client.GetInConn(typ)
if err != nil && strings.Contains(err.Error(), "write connection data err") {
time.Sleep(backoff) // conn already closed by lib; just retry
conn, err = client.GetInConn(typ)
} Prevention
- Match the client key exactly with the server key config
- Enable TCP keepalive and retry with exponential backoff on flaky links
- Watch server logs for simultaneous close events to catch auth/version mismatch
- Avoid restarting the server during active client handshakes; drain first
When it happens
Trigger: outConn.Write(pkg.Bytes()) fails after the connection was established — typically because the server closed the conn right after accept (auth/key rejected, TLS failure, server restarting) or the network dropped mid-write; GetInConn closes outConn and returns the wrapped error.
Common situations: Mismatched client key so the server drops the connection; server restarted between accept and read; intermediate proxy/firewall RSTs the connection; unstable mobile/VPN network dropping packets.
Related errors
- connection err: %s
- client control conn not exists
- no address Found, net.InterfaceAddrs: %v
- http decoder read err:%s
AI-assisted analysis of snail007/goproxy@e6d6a821db (2026-09-03).
Data as JSON: /api/errors/8fd8eecfc0075df6.
Report an issue: GitHub.