{"record":{"id":"d5e6083c90a2e41a","repo":"slackhq/nebula","slug":"unmarshal-handshake-w","errorCode":null,"errorMessage":"unmarshal handshake: %w","messagePattern":"unmarshal handshake: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"handshake/machine.go","lineNumber":297,"sourceCode":"\tm.result.EKey = eKey\n\tm.result.DKey = dKey\n\tm.result.MessageIndex = uint64(m.hs.MessageIndex())\n\treturn m.result\n}\n\nfunc (m *Machine) processPayload(msg []byte, flags msgFlags) error {\n\tif len(msg) == 0 {\n\t\tif flags.expectsPayload || flags.expectsCert {\n\t\t\tm.failed = true\n\t\t\treturn ErrMissingContent\n\t\t}\n\t\treturn nil\n\t}\n\n\tpayload, err := UnmarshalPayload(msg)\n\tif err != nil {\n\t\tm.failed = true\n\t\treturn fmt.Errorf(\"unmarshal handshake: %w\", err)\n\t}\n\n\t// Assert the payload contains exactly what we expect\n\thasPayloadData := payload.InitiatorIndex != 0 || payload.ResponderIndex != 0 || payload.Time != 0\n\tif hasPayloadData != flags.expectsPayload {\n\t\tm.failed = true\n\t\treturn ErrUnexpectedContent\n\t}\n\n\thasCertData := len(payload.Cert) > 0\n\tif hasCertData != flags.expectsCert {\n\t\tm.failed = true\n\t\treturn ErrUnexpectedContent\n\t}\n\n\t// Process payload\n\tif flags.expectsPayload {\n\t\tvar remoteIndex uint32","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/handshake/machine.go#L279-L315","documentation":"processPayload wraps errors from UnmarshalPayload as 'unmarshal handshake: %w' and marks the machine failed. The Noise handshake message decrypted successfully, but its Nebula handshake payload bytes could not be deserialized — the payload structure is not a valid handshake Payload protobuf.","triggerScenarios":"ProcessPacket -> processPayload on a successfully decrypted Noise message whose plaintext is not a well-formed Payload (wrong version encoding, corrupted inner bytes, or a foreign implementation's payload layout).","commonSituations":"Mixed Nebula versions with incompatible payload encodings, a third-party Noise peer speaking the same pattern but different payload schema, bit corruption surviving the AEAD check (rare), faked packets from an attacker holding a derived key.","solutions":["Upgrade/downgrade peers to a Nebula version with a compatible handshake payload encoding","Start a fresh handshake (machine is marked failed; the existing Machine cannot retry)","Confirm the remote endpoint actually runs Nebula and not another Noise-protocol service","Check for packet corruption on the path (NIC offload bugs, tunnel-in-tunnel MTU issues)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"_, _, err := machine.ProcessPacket(pkt)\nif err != nil && strings.Contains(err.Error(), \"unmarshal handshake:\") {\n\t// machine is marked failed — tear it down and start a new handshake\n\tconnManager.resetHandshake(remote)\n}","preventionTips":["Keep Nebula versions aligned across the deployment (payload encoding changes between versions)","Reject traffic from non-Nebula Noise services sharing the port","Watch for hardware/offload corruption issues and disable problematic NIC offloads","Log the remote address on this error to identify misbehaving peers"],"tags":["handshake","payload","deserialization"],"backgroundTag":"handshake-payload-unmarshal-failed","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"}