{"record":{"id":"13da12a01cb9ffe1","repo":"slackhq/nebula","slug":"errasymmetriccipherkeys","errorCode":"ErrAsymmetricCipherKeys","errorMessage":"noise produced only one cipher key","messagePattern":"noise produced only one cipher key","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"handshake/errors.go","lineNumber":19,"sourceCode":"package handshake\n\nimport \"errors\"\n\nvar (\n\tErrInitiateOnResponder     = errors.New(\"initiate called on responder\")\n\tErrInitiateAlreadyCalled   = errors.New(\"initiate already called\")\n\tErrInitiateNotCalled       = errors.New(\"initiate must be called before ProcessPacket for initiators\")\n\tErrPacketTooShort          = errors.New(\"packet too short\")\n\tErrPublicKeyMismatch       = errors.New(\"public key mismatch between certificate and handshake\")\n\tErrIncompleteHandshake     = errors.New(\"handshake completed without receiving required content\")\n\tErrMachineFailed           = errors.New(\"handshake machine has failed\")\n\tErrUnknownSubtype          = errors.New(\"unknown handshake subtype\")\n\tErrMissingContent          = errors.New(\"expected handshake content but message was empty\")\n\tErrUnexpectedContent       = errors.New(\"received unexpected handshake content\")\n\tErrInvalidRemoteIndex      = errors.New(\"peer sent an invalid index in handshake payload\")\n\tErrIndexAllocation         = errors.New(\"failed to allocate local index\")\n\tErrNoCredential            = errors.New(\"no handshake credential available for cert version\")\n\tErrAsymmetricCipherKeys    = errors.New(\"noise produced only one cipher key\")\n\tErrMultiMessageUnsupported = errors.New(\"multi-message handshake patterns are not yet supported by the manager\")\n\tErrSubtypeMismatch         = errors.New(\"packet subtype does not match handshake machine subtype\")\n)\n","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/handshake/errors.go#L1-L23","documentation":"ErrAsymmetricCipherKeys is returned by ProcessPacket when a Noise handshake message that should finalize key derivation yields only one of the two transport cipher keys (encryption or decryption key is nil). A correct handshake always produces a key pair for both directions, so this indicates a pattern/engine inconsistency. The machine is marked failed.","triggerScenarios":"In ProcessPacket, after the final handshake stage, eKey == nil || dKey == nil (handshake/machine.go:249) or ek == nil || dk == nil (machine.go:267) — NoiseCipherResults returned fewer than two cipher keys.","commonSituations":"Bug or mismatch in the handshake pattern implementation (wrong message count for the chosen pattern); peers using different pattern definitions so one side finalizes too early; corrupted handshake state from reusing a machine.","solutions":["Verify both peers use a handshake pattern whose message count matches the implementation's expectations","Upgrade the library in case of a Noise key-derivation bug in your version","Restart the handshake with a fresh Machine; never reuse partially completed machines"],"exampleFix":"// before: pattern declared with fewer messages than needed\npattern := handshake.PatternIK1 // only 1 message; final stage has no 2nd key\n\n// after\npattern := handshake.PatternIK // full pattern produces both cipher keys","handlingStrategy":"try-catch","validationCode":"if patternMsgCount(pattern) != expectedStages {\n    return fmt.Errorf(\"pattern %v produces asymmetric keys: wrong stage count\", pattern)\n}","typeGuard":"func keysSymmetric(res handshake.CipherResults) bool {\n    return res.EKey != nil && res.DKey != nil\n}","tryCatchPattern":"res, _, err := m.ProcessPacket(out, pkt)\nif errors.Is(err, handshake.ErrAsymmetricCipherKeys) {\n    // key derivation is broken: abort and restart from a fresh machine\n    conn.Close()\n    log.Printf(\"noise produced asymmetric cipher keys with %s\", conn.RemoteAddr())\n    return\n}","preventionTips":["Use only vetted, complete handshake patterns with matching message counts on both peers","Never reuse a Machine across handshakes — corrupted state can derail key derivation","Upgrade promptly when the library patches Noise derivation bugs"],"tags":["handshake","noise","cryptography"],"backgroundTag":"key-derivation-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"}