XTLS/Xray-core · warning
discarding fragmented payload.
Error message
discarding fragmented payload.
What it means
Thrown when decoding a SOCKS5 UDP packet whose fragment byte (byte 2 of the header) is non-zero, meaning the client used SOCKS5 UDP fragmentation (RFC 1928 FRAG). Xray does not reassemble fragmented UDP datagrams, so it discards them instead of delivering corrupt payloads.
Source
Thrown at proxy/socks/protocol.go:355
common.Must(buffer.WriteByte(errCode))
portBytes := buffer.Extend(2)
binary.BigEndian.PutUint16(portBytes, port.Value())
common.Must2(buffer.Write(address.IP()))
return buf.WriteAllBytes(writer, buffer.Bytes(), nil)
}
func DecodeUDPPacket(packet *buf.Buffer) (*protocol.RequestHeader, error) {
if packet.Len() < 5 {
return nil, errors.New("insufficient length of packet.")
}
request := &protocol.RequestHeader{
Version: socks5Version,
Command: protocol.RequestCommandUDP,
}
// packet[0] and packet[1] are reserved
if packet.Byte(2) != 0 /* fragments */ {
return nil, errors.New("discarding fragmented payload.")
}
packet.Advance(3)
addr, port, err := addrParser.ReadAddressPort(nil, packet)
if err != nil {
return nil, errors.New("failed to read UDP header").Base(err)
}
request.Address = addr
request.Port = port
return request, nil
}
func EncodeUDPPacket(request *protocol.RequestHeader, data []byte) (*buf.Buffer, error) {
b := buf.New()
common.Must2(b.Write([]byte{0, 0, 0 /* Fragment */}))
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {
b.Release()View on GitHub (pinned to 7d214f8b09)
Solutions
- Configure the client SOCKS5 library to disable SOCKS-level fragmentation (always send FRAG=0 and rely on IP fragmentation or smaller payloads).
- Lower the client application's UDP datagram size below the path MTU so fragmentation is never attempted.
- If you cannot change the client, switch the tunnel to a transport that carries UDP natively without SOCKS framing.
Example fix
// client side, e.g. go-socks5 style writer // before header[2] = fragNumber // FRAG != 0 // after header[2] = 0 // never SOCKS-fragment; keep datagrams whole _ = fragNumber
Defensive patterns
Strategy: validation
Validate before calling
// before decoding, check the fragment byte
if packet.Len() >= 3 && packet.Byte(2) != 0 {
// client used SOCKS5 fragmentation; unsupported
packet.Release()
continue
} Try / catch
if _, err := socks.DecodeUDPPacket(packet); err != nil && strings.Contains(err.Error(), "fragmented") {
metrics.FragmentedDrops++
continue
} Prevention
- Configure client SOCKS5 stacks to always send FRAG=0.
- Cap application UDP datagram size below path MTU.
- Prefer transports with native UDP for fragmentation-prone traffic.
When it happens
Trigger: A SOCKS5 client sends UDP ASSOCIATE traffic with FRAG != 0 — i.e. it split a large datagram into fragments per RFC 1928. Any client that sets the fragment field (some tun2socks stacks, rare BitTorrent/DHT implementations) triggers this on every fragmented datagram.
Common situations: Large UDP payloads exceeding the client's path MTU where the client's SOCKS library fragments rather than relying on IP fragmentation; legacy or spec-literal SOCKS5 client libraries; games or VoIP with oversized datagrams.
Related errors
- UDP is not enabled.
- insufficient length of packet.
- failed to read UDP header
- failed to read auth methods
- no matching auth method
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/ab3c6191d4ed0754.
Report an issue: GitHub.