XTLS/Xray-core · error
insufficient header
Error message
insufficient header
What it means
Thrown by ServerSession.handshake4 (proxy/socks/protocol.go:65) when reading the fixed 6-byte SOCKS4 request body (2-byte port + 4-byte IP) fails. ReadFullFrom requires exactly 6 bytes, so the error means the peer sent fewer bytes than needed and the stream ended (EOF/timeout/reset) before the header was complete.
Source
Thrown at proxy/socks/protocol.go:65
address net.Address
port net.Port
localAddress net.Address
}
func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
if s.config.AuthType == AuthType_PASSWORD {
writeSocks4Response(writer, socks4RequestRejected, net.AnyIP, net.Port(0))
return nil, errors.New("socks 4 is not allowed when auth is required.")
}
var port net.Port
var address net.Address
{
buffer := buf.StackNew()
if _, err := buffer.ReadFullFrom(reader, 6); err != nil {
buffer.Release()
return nil, errors.New("insufficient header").Base(err)
}
port = net.PortFromBytes(buffer.BytesRange(0, 2))
address = net.IPAddress(buffer.BytesRange(2, 6))
buffer.Release()
}
if _, err := ReadUntilNull(reader); /* user id */ err != nil {
return nil, err
}
if address.IP()[0] == 0x00 {
domain, err := ReadUntilNull(reader)
if err != nil {
return nil, errors.New("failed to read domain for socks 4a").Base(err)
}
address = net.ParseAddress(domain)
}
switch cmd {View on GitHub (pinned to 7d214f8b09)
Solutions
- Verify the client actually speaks SOCKS4/4a and sends the full request: VER(1) CMD(1) DSTPORT(2) DSTIP(4) USERID(nul).
- Check the base error: EOF means the peer closed early (client bug); timeout means a stalled or probing connection.
- Reproduce with a known-good client (curl --socks4) to confirm the server config is fine; if it works, fix or replace the custom client.
- If the source is a scanner, restrict inbound exposure (firewall/bind to trusted interface).
Example fix
// before: half-written SOCKS4 request
conn.Write([]byte{0x04, 0x01, 0x00}) // only 3 bytes, then closed
// after: complete SOCKS4 CONNECT header (port 80, IP 93.184.216.34, empty userid)
conn.Write([]byte{0x04, 0x01, 0x00, 0x50, 93, 184, 216, 34, 0x00}) Defensive patterns
Strategy: try-catch
Try / catch
header, udpConn, err := session.Handshake(reader, conn)
if err != nil {
if strings.Contains(err.Error(), "insufficient header") {
// peer sent a truncated or probe request: log at debug and close quietly
logDebug("truncated socks4 request from %v", conn.RemoteAddr())
}
return err
} Prevention
- Write complete SOCKS4 frames in a single conn.Write call.
- Verify client framing with a reference implementation before shipping.
- Expect scanners on any exposed SOCKS port and keep logging at a level that tolerates the noise.
When it happens
Trigger: A client that writes the SOCKS4 version/command bytes and then closes, resets, or stalls the connection before sending the remaining 6 bytes; a scanner or health-check that only writes 2 probe bytes; a truncated client implementation.
Common situations: Port scanners / idle probers hitting the SOCKS port; broken or half-implemented SOCKS4 clients; network middleboxes truncating small packets; TCP connection cut right after handshake start.
Related errors
- failed to read request
- failed to read auth methods
- failed to read address
- connection ends
- socks 4 is not allowed when auth is required.
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/48dff0512b0499f0.
Report an issue: GitHub.