{"record":{"id":"a0aacd420005d34f","repo":"OpenNHP/opennhp","slug":"missing-connection-data-for-server","errorCode":null,"errorMessage":"missing connection data for server","messagePattern":"missing connection data for server","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nhp/core/initiator.go","lineNumber":44,"sourceCode":"\tConnData       *ConnectionData   // used by server to pick an existing connection for msg sending\n\tPrevParserData *PacketParserData // when PrevParserData is set, CipherScheme, RemoteAddr, ConnData, TransactionId and PeerPk will be overridden\n\tCipherScheme   int               // 0: curve25519/aes-256-gcm/blake2s (CIPHER_SCHEME_CURVE), 1: sm2/sm4-gcm/sm3 (CIPHER_SCHEME_GMSM)\n\tTransactionId  uint64\n\tHeaderType     int\n\tCompress       bool\n\tClPkc          bool // 0: non-CL-PKC extented, 1: CL-PKC extended\n\tExternalPacket *Packet\n\tExternalCookie *[CookieSize]byte\n\tMessage        []byte\n\tPeerPk         []byte\n\tEncryptedPktCh chan *MsgAssemblerData\n\tResponseMsgCh  chan *PacketParserData\n}\n\nfunc (d *Device) validateMsgData(md *MsgData) (err error) {\n\tif md.PrevParserData == nil {\n\t\tif d.deviceType == NHP_SERVER && md.ConnData == nil {\n\t\t\terr = fmt.Errorf(\"missing connection data for server\")\n\t\t} else if d.deviceType != NHP_SERVER && md.RemoteAddr == nil {\n\t\t\terr = fmt.Errorf(\"missing remote address\")\n\t\t}\n\n\t\tif md.PeerPk == nil {\n\t\t\terr = fmt.Errorf(\"missing remote peer public key\")\n\t\t}\n\t}\n\n\treturn err\n}\n\ntype MsgAssemblerData struct {\n\tdevice     *Device\n\tBasePacket *Packet\n\tconnData   *ConnectionData\n\tciphers    *CipherSuite\n","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/core/initiator.go#L26-L62","documentation":"Device.validateMsgData requires a ConnData when the local device is an NHP_SERVER and the message has no PrevParserData (i.e. it is the first message of a new transaction). Server-side message encryption/decryption is driven by the stored connection state; without it the server cannot derive keys for the message.","triggerScenarios":"Calling server-side MsgToPacket/processing with a MsgData whose ConnData is nil and PrevParserData is nil, e.g. responding to a knock whose connection record was never created or already expired.","commonSituations":"Server restarted and lost in-memory connection state while an agent retransmits; custom code building MsgData by hand for testing; connection entry evicted before the reply is sent.","solutions":["Ensure the ConnData produced during packet parsing is carried into the MsgData used for the reply","Do not construct MsgData manually for server-side sends; reuse the ConnData from PacketToMsg","If the connection expired, drop the message instead of replying, forcing the agent to re-knock","Check for code paths that nil out ConnData (e.g. after transaction completion) before response assembly"],"exampleFix":"// before\nmd := &MsgData{TransactionId: txnId} // ConnData missing\n// after\nmd := &MsgData{TransactionId: txnId, ConnData: connData, PeerPk: peerPk}","handlingStrategy":"validation","validationCode":"if md.PrevParserData == nil && md.ConnData == nil {\n    return errors.New(\"server-side send requires ConnData\")\n}","typeGuard":"func serverMsgReady(md *nhpcore.MsgData) bool { return md.PrevParserData != nil || md.ConnData != nil }","tryCatchPattern":"if err := send(md); errors.Is(err, nhpcore.ErrMissingConnData) {\n    // drop; agent will re-knock\n}","preventionTips":["Always derive MsgData from the PacketParserData of the incoming packet","Never hand-build server replies without their ConnData","Watch for connection-state expiry racing with replies"],"tags":["go","protocol","state"],"backgroundTag":"missing-required-argument","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"}