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

  1. Verify the client actually speaks SOCKS4/4a and sends the full request: VER(1) CMD(1) DSTPORT(2) DSTIP(4) USERID(nul).
  2. Check the base error: EOF means the peer closed early (client bug); timeout means a stalled or probing connection.
  3. Reproduce with a known-good client (curl --socks4) to confirm the server config is fine; if it works, fix or replace the custom client.
  4. 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

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


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/48dff0512b0499f0. Report an issue: GitHub.