slackhq/nebula · warning
ErrIPv6CouldNotFindPayload
ErrIPv6CouldNotFindPayload
Error message
could not find payload in ipv6 packet
What it means
ErrIPv6CouldNotFindPayload is returned by IPv6FindUpperProtocol when the packet is too short to hold an IPv6 header or the extension header chain (hop-by-hop, routing, destination, fragment) is truncated before a terminal upper-layer protocol is reached, within the 8-extension-header limit.
Source
Thrown at iputil/packet.go:13
package iputil
import (
"encoding/binary"
"errors"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
// ErrIPv6CouldNotFindPayload is returned when the ipv6 extension header chain is truncated before a terminal
// upper layer protocol is reached.
var ErrIPv6CouldNotFindPayload = errors.New("could not find payload in ipv6 packet")
const (
// MaxIPv4RejectPacketSize is the largest IPv4 reject packet:
// - 20 byte ipv4 header
// - 8 byte icmpv4 header
// - 68 byte body (60 byte max orig ipv4 header + 8 byte orig icmpv4 header)
maxIPv4RejectPacketSize = ipv4.HeaderLen + 8 + 60 + 8
// MaxRejectPacketSize is sized for the largest possible reject packet (IPv6):
// - 40 byte ipv6 header
// - 8 byte icmpv6 header
// - up to 1000 byte body (original packet, possibly truncated. We want to stay
// under the MTU with Nebula overhead included)
maxIPv6RejectPacketSize = ipv6.HeaderLen + 8 + 1000
MaxRejectPacketSize = maxIPv6RejectPacketSize
IPProtocolICMP = 1View on GitHub (pinned to dd8f660c0a)
Solutions
- Check NIC offload/MTU settings and capture path for truncation
- Validate the packet length before parsing; treat the packet as malformed and drop it
- If this is your code calling IPv6FindUpperProtocol, guard on len(packet) >= ipv6.HeaderLen first
- Use errors.Is(err, ErrIPv6CouldNotFindPayload) to distinguish malformed packets from real protocol data
Example fix
// before
nh, off, frag, anyFrag, err := IPv6FindUpperProtocol(packet)
handle(nh, off)
// after
nh, off, frag, anyFrag, err := IPv6FindUpperProtocol(packet)
if errors.Is(err, ErrIPv6CouldNotFindPayload) {
// malformed/truncated ipv6 packet: drop
return
} Defensive patterns
Strategy: try-catch
Validate before calling
if len(packet) < 40 { // ipv6.HeaderLen
// too short to be an ipv6 packet; skip parse
} Type guard
func isParseableIPv6(packet []byte) bool { return len(packet) >= 40 } Try / catch
nh, off, frag, anyFrag, err := IPv6FindUpperProtocol(packet)
if errors.Is(err, ErrIPv6CouldNotFindPayload) {
// truncated/malformed extension chain: drop or log counter
return
} Prevention
- Guard packet length before parsing
- Drop and count malformed packets instead of retrying
- Watch for MTU/offload truncation in your capture path
- Use errors.Is, not string comparison, against the sentinel error
When it happens
Trigger: Parsing a packet shorter than ipv6.HeaderLen; an extension header claims more bytes than remain (len(packet) < offset+2); a fragment header encountered without a following payload; more than maxIPv6ExtHeaders extension headers.
Common situations: Corrupt or truncated packets from a bad NIC/MTU mismatch; malicious malformed packets hitting the firewall path; reading a partial buffer from the UDP socket.
Related errors
- ErrBadDetailsVpnAddr
- ErrIPv6PacketTooShort
- ErrInvalidIPv6RemoteForSocket
- unable to find host
- unable to find host with relay
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/7d4b478194615f50.
Report an issue: GitHub.