ginuerzh/gost · error
kcp: wrong connection type
Error message
kcp: wrong connection type
What it means
kcpTransporter.initSession requires the conn it received to implement net.PacketConn, because the KCP protocol is built on top of UDP-style packet sockets. If the handed-over connection is a stream conn (e.g. *net.TCPConn or a wrapped/tunneled conn), it returns this error before creating the KCP session.
Source
Thrown at kcp.go:219
return nil, err
}
session = s
tr.sessions[opts.Addr] = session
}
cc, err := session.GetConn()
if err != nil {
session.Close()
delete(tr.sessions, opts.Addr)
return nil, err
}
return cc, nil
}
func (tr *kcpTransporter) initSession(addr string, conn net.Conn, config *KCPConfig) (*muxSession, error) {
pc, ok := conn.(net.PacketConn)
if !ok {
return nil, errors.New("kcp: wrong connection type")
}
kcpconn, err := kcp.NewConn(addr,
blockCrypt(config.Key, config.Crypt, KCPSalt),
config.DataShard, config.ParityShard, pc)
if err != nil {
return nil, err
}
kcpconn.SetStreamMode(true)
kcpconn.SetWriteDelay(false)
kcpconn.SetNoDelay(config.NoDelay, config.Interval, config.Resend, config.NoCongestion)
kcpconn.SetWindowSize(config.SndWnd, config.RcvWnd)
kcpconn.SetMtu(config.MTU)
kcpconn.SetACKNoDelay(config.AckNodelay)
if config.DSCP > 0 {
if err := kcpconn.SetDSCP(config.DSCP); err != nil {View on GitHub (pinned to a33fdbf4c9)
Solutions
- Ensure the kcp transport dials via its own UDP dialer so a net.PacketConn is passed to initSession.
- Do not wrap the conn in intermediaries before kcp.Handshake; if wrapping is required, implement/unwrap to expose net.PacketConn.
- Verify node/chain config so kcp:// URLs use the kcp dialer, not the tcp one.
- If you must run KCP over a stream, use a KCP variant that supports stream conns instead of this transporter.
Example fix
// before
conn, _ := net.Dial("tcp", addr) // stream conn
session, err := kcpTransporter.Handshake(conn, addr)
// after
conn, err := net.Dial("udp", addr) // PacketConn
session, err := kcpTransporter.Handshake(conn, addr) Defensive patterns
Strategy: validation
Validate before calling
if _, ok := conn.(net.PacketConn); !ok {
return errors.New("kcp handshake requires a net.PacketConn (UDP) connection")
} Type guard
func isPacketConn(c net.Conn) (net.PacketConn, bool) {
pc, ok := c.(net.PacketConn)
return pc, ok
} Try / catch
session, err := tr.Handshake(conn, addr)
if err != nil && strings.Contains(err.Error(), "wrong connection type") {
// dial UDP and retry
pc, derr := net.Dial("udp", addr)
if derr != nil { return derr }
session, err = tr.Handshake(pc, addr)
} Prevention
- Always dial UDP when using the kcp transport; never feed TCP conns into it.
- Avoid wrapping conns before kcp.Handshake so the concrete PacketConn type survives.
- Validate transport/dialer pairing in config at startup.
When it happens
Trigger: Calling Handshake on the kcp transporter with a conn that is not a net.PacketConn — e.g. configuring the kcp transport but the dialer produced a stream connection, or passing a wrapped/muxed conn into initSession via Handshake.
Common situations: Misconfigured transport chain (kcp selected but underlying dialer is TCP); proxy chains wrapping conns so the concrete PacketConn type is lost; passing a net.Conn from another transport into the kcp handshake path.
Related errors
- not a packet connection
- accpet on closed listener
- wrong connection type
- accpet on closed listener
- ciphertext too short
AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02).
Data as JSON: /api/errors/cd402697f9168a45.
Report an issue: GitHub.