{"record":{"id":"f9ce4db493057463","repo":"cloudflare/cloudflared","slug":"failed-to-parse-icmpv4-message","errorCode":null,"errorMessage":"failed to parse ICMPv4 message","messagePattern":"failed to parse ICMPv4 message","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packet/decoder.go","lineNumber":158,"sourceCode":"}\n\nfunc (pd *ICMPDecoder) Decode(packet RawPacket) (*ICMP, error) {\n\t// Should decode to IP and optionally ICMP layer\n\tdecoded, err := pd.decodeByVersion(packet.Data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, layerType := range decoded {\n\t\tswitch layerType {\n\t\tcase layers.LayerTypeICMPv4:\n\t\t\tipv4, err := newIPv4(pd.ipv4)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tmsg, err := icmp.ParseMessage(int(layers.IPProtocolICMPv4), append(pd.icmpv4.Contents, pd.icmpv4.Payload...))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Wrap(err, \"failed to parse ICMPv4 message\")\n\t\t\t}\n\t\t\treturn &ICMP{\n\t\t\t\tIP:      ipv4,\n\t\t\t\tMessage: msg,\n\t\t\t}, nil\n\t\tcase layers.LayerTypeICMPv6:\n\t\t\tipv6, err := newIPv6(pd.ipv6)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tmsg, err := icmp.ParseMessage(int(layers.IPProtocolICMPv6), append(pd.icmpv6.Contents, pd.icmpv6.Payload...))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Wrap(err, \"failed to parse ICMPv6\")\n\t\t\t}\n\t\t\treturn &ICMP{\n\t\t\t\tIP:      ipv6,\n\t\t\t\tMessage: msg,\n\t\t\t}, nil","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/packet/decoder.go#L140-L176","documentation":"Decoder.Decode reconstructs ICMPv4 packets: after parsing the IPv4 header, it feeds the concatenated ICMP header+payload bytes to golang.org/x/net/icmp's ParseMessage. If those bytes are not a valid ICMPv4 message, the parse error is wrapped with this message and Decode returns nil error result.","triggerScenarios":"Calling packet.Decoder.Decode (via handlePacket/handleFullPacket on QUIC/UDP datagrams) with a packet whose ICMPv4 contents/payload are truncated or malformed, so icmp.ParseMessage fails.","commonSituations":"Corrupted or truncated datagrams from the edge, packets reassembled incorrectly, or tests feeding synthetic bytes that do not form valid ICMPv4 (see TestDecodeBadPackets).","solutions":["Log the raw packet bytes to confirm the ICMPv4 header (type/code/checksum) is complete and well-formed.","Verify the sender/edge is forwarding full ICMP datagrams without truncation.","Handle the decode error gracefully (drop the packet) — for a tunnel proxy this usually indicates a corrupt datagram, not a local bug.","If reproducing in tests, build messages with icmp.Message.Marshal instead of hand-crafted bytes."],"exampleFix":"// before\nc, err := decoder.Decode(rawPacket)\nif err != nil { return err }\n// after\nc, err := decoder.Decode(rawPacket)\nif err != nil {\n    log.Debug().Err(err).Msg(\"dropping malformed icmp packet\")\n    return nil // skip malformed packet\n}","handlingStrategy":"try-catch","validationCode":"// Sanity check before decode: at least an IPv4 header + 8-byte ICMP header\nfunc plausiblyICMPv4(b []byte) bool {\n    if len(b) < 28 {\n        return false\n    }\n    return b[9] == 1 // protocol == ICMP\n}","typeGuard":null,"tryCatchPattern":"decoded, err := decoder.Decode(raw)\nif err != nil {\n    log.Debug().Err(err).Msg(\"dropping undecodable packet\")\n    return nil\n}","preventionTips":["Treat decode failures on individual datagrams as non-fatal; drop and continue.","Verify MTU along the tunnel path to avoid truncated payloads.","In tests, marshal ICMP messages with x/net/icmp instead of hand-built bytes."],"tags":["icmp","packet-decoding","network"],"backgroundTag":"invalid-argument-value","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}