{"record":{"id":"678b737da6845cbf","repo":"slackhq/nebula","slug":"errincompletehandshake","errorCode":"ErrIncompleteHandshake","errorMessage":"handshake completed without receiving required content","messagePattern":"handshake completed without receiving required content","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"handshake/errors.go","lineNumber":11,"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":"ErrIncompleteHandshake is returned by requireComplete when the handshake finishes (Noise exchange done) but the machine never received the required payload and/or remote certificate. The pattern flags indicate these contents are mandatory, so completing without them means the peer sent malformed or truncated handshake messages. The machine is marked failed when this occurs.","triggerScenarios":"requireComplete (handshake/machine.go:135) runs after the final handshake message and m.payloadSet or m.remoteCertSet is still false; tested in machine_test.go:266 by calling m.requireComplete() directly on a machine that received no content.","commonSituations":"Peer software version omits the payload/cert in its final message; a packet was dropped or the peer crashed mid-handshake; pattern flags were changed without updating the peer.","solutions":["Ensure the peer sends payload and certificate in the messages whose pattern flags expect them","Re-run the handshake; transient packet loss can leave content unset","Check that both peers use the same handshake pattern/subtype so flags agree"],"exampleFix":"// before: final message written without payload\nout := m.WriteMessage() // no AppendPayload / AppendCert\n\n// after: attach required content before sending the final message\nout = m.AppendPayload(out, payload)\nout = m.AppendCert(out, cert)","handlingStrategy":"retry","validationCode":"if m.Failed() {\n    return fmt.Errorf(\"machine already failed; recreate before handshake\")\n}","typeGuard":"func handshakeComplete(m *handshake.Machine) bool {\n    return !m.Failed() && m.Result().RemoteIndex != 0\n}","tryCatchPattern":"res, err := m.ProcessPacket(out, pkt)\nif errors.Is(err, handshake.ErrIncompleteHandshake) {\n    // peer omitted required content: restart handshake with a fresh machine\n    m, err = handshake.NewMachine(cs, version, getCred)\n    return retryHandshake(m)\n}","preventionTips":["Keep both peers on library versions with identical pattern/message layouts","Run integration tests exercising the full handshake between versions","Treat any requireComplete failure as protocol incompatibility, not transient"],"tags":["handshake","protocol","noise"],"backgroundTag":"handshake-incomplete","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"}