{"record":{"id":"7d4b478194615f50","repo":"slackhq/nebula","slug":"erripv6couldnotfindpayload","errorCode":"ErrIPv6CouldNotFindPayload","errorMessage":"could not find payload in ipv6 packet","messagePattern":"could not find payload in ipv6 packet","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"iputil/packet.go","lineNumber":13,"sourceCode":"package iputil\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\n\t\"golang.org/x/net/ipv4\"\n\t\"golang.org/x/net/ipv6\"\n)\n\n// ErrIPv6CouldNotFindPayload is returned when the ipv6 extension header chain is truncated before a terminal\n// upper layer protocol is reached.\nvar ErrIPv6CouldNotFindPayload = errors.New(\"could not find payload in ipv6 packet\")\n\nconst (\n\t// MaxIPv4RejectPacketSize is the largest IPv4 reject packet:\n\t// - 20 byte ipv4 header\n\t// - 8 byte icmpv4 header\n\t// - 68 byte body (60 byte max orig ipv4 header + 8 byte orig icmpv4 header)\n\tmaxIPv4RejectPacketSize = ipv4.HeaderLen + 8 + 60 + 8\n\n\t// MaxRejectPacketSize is sized for the largest possible reject packet (IPv6):\n\t// - 40 byte ipv6 header\n\t// - 8 byte icmpv6 header\n\t// - up to 1000 byte body (original packet, possibly truncated. We want to stay\n\t//   under the MTU with Nebula overhead included)\n\tmaxIPv6RejectPacketSize = ipv6.HeaderLen + 8 + 1000\n\n\tMaxRejectPacketSize = maxIPv6RejectPacketSize\n\n\tIPProtocolICMP        = 1","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/iputil/packet.go#L1-L31","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nnh, off, frag, anyFrag, err := IPv6FindUpperProtocol(packet)\nhandle(nh, off)\n// after\nnh, off, frag, anyFrag, err := IPv6FindUpperProtocol(packet)\nif errors.Is(err, ErrIPv6CouldNotFindPayload) {\n    // malformed/truncated ipv6 packet: drop\n    return\n}","handlingStrategy":"try-catch","validationCode":"if len(packet) < 40 { // ipv6.HeaderLen\n    // too short to be an ipv6 packet; skip parse\n}","typeGuard":"func isParseableIPv6(packet []byte) bool { return len(packet) >= 40 }","tryCatchPattern":"nh, off, frag, anyFrag, err := IPv6FindUpperProtocol(packet)\nif errors.Is(err, ErrIPv6CouldNotFindPayload) {\n    // truncated/malformed extension chain: drop or log counter\n    return\n}","preventionTips":["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"],"tags":["network","ipv6","packet-parsing","nebula"],"backgroundTag":"malformed-packet","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}