{"record":{"id":"b22218f77874ae6f","repo":"OpenNHP/opennhp","slug":"keepalive-packet-size-is-incorrect","errorCode":null,"errorMessage":"keepalive packet size is incorrect","messagePattern":"keepalive packet size is incorrect","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"nhp/core/packet.go","lineNumber":249,"sourceCode":"\t\tswitch t {\n\t\tcase NHP_DRG, NHP_DAG, NHP_DAK, NHP_DBA, NHP_DWR:\n\t\t\treturn true\n\t\t}\n\t}\n\tlog.Info(\"Device type: %d, recv header type %d not allowed\", d.deviceType, t)\n\treturn false\n}\n\nfunc (d *Device) RecvPrecheck(pkt *Packet) (int, int, error) {\n\theaderSize := pkt.Header().Size()\n\n\t// check type and payload size\n\tt, s := pkt.HeaderTypeAndSize()\n\tif t == NHP_KPL {\n\t\tif s == 0 {\n\t\t\treturn t, s, nil\n\t\t} else {\n\t\t\treturn t, s, fmt.Errorf(\"keepalive packet size is incorrect\")\n\t\t}\n\t}\n\tif !d.CheckRecvHeaderType(t) {\n\t\treturn t, s, fmt.Errorf(\"packet header type does not match device\")\n\t}\n\n\ttotalLen := len(pkt.Content)\n\tif totalLen != headerSize+s {\n\t\treturn t, s, fmt.Errorf(\"packet total size is incorrect\")\n\t}\n\n\treturn t, s, nil\n}\n\nfunc (d *Device) AllocatePoolPacket() *Packet {\n\tbuf := d.pool.Get()\n\treturn &Packet{Buf: buf, Content: buf[:], PoolAllocated: true}\n}","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/core/packet.go#L231-L267","documentation":"Device.RecvPrecheck validates an incoming packet's header before decryption. NHP keepalive packets (NHP_KPL) must carry zero payload; any nonzero size is rejected with this error. It guards against keepalives carrying unexpected data.","triggerScenarios":"recvPacketRoutine, HandleRelayForward, or PacketToMsg receives a packet whose header type is NHP_KPL but whose declared payload size (s) is nonzero.","commonSituations":"Interoperating with a peer implementation that appends data to keepalives; version mismatch where keepalive format changed; packet corruption flipping size bytes on the wire.","solutions":["Fix the sender so keepalive packets are sent with an empty payload","Upgrade/align both endpoints to the same NHP protocol version","If corruption is suspected, check network path/MTU and UDP checksums","For testing, build keepalives via the library's packet constructor, not hand-crafted bytes"],"exampleFix":"// before\npkt := dev.AllocatePoolPacket()\npkt.SetHeaderTypeAndSize(nhpcore.NHP_KPL, len(payload)) // payload on keepalive\n// after\npkt := dev.AllocatePoolPacket()\npkt.SetHeaderTypeAndSize(nhpcore.NHP_KPL, 0) // keepalives are empty","handlingStrategy":"validation","validationCode":"t, s := pkt.HeaderTypeAndSize()\nif t == nhpcore.NHP_KPL && s != 0 {\n    return errors.New(\"keepalive with payload\")\n}","typeGuard":"func isBareKeepalive(pkt *nhpcore.Packet) bool {\n    t, s := pkt.HeaderTypeAndSize()\n    return t == nhpcore.NHP_KPL && s == 0\n}","tryCatchPattern":"t, s, err := dev.RecvPrecheck(pkt)\nif err != nil && strings.Contains(err.Error(), \"keepalive packet size\") {\n    log.Warnf(\"bad keepalive from %v\", sender)\n    continue\n}","preventionTips":["Send keepalives only through the library's keepalive constructor","Keep both endpoints on the same protocol version","Monitor sender implementations after protocol changes"],"tags":["go","protocol","keepalive"],"backgroundTag":"invalid-argument-format","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}