{"record":{"id":"750ebbc43927d223","repo":"slackhq/nebula","slug":"errmessagecounterexhausted","errorCode":"ErrMessageCounterExhausted","errorMessage":"message counter exhausted","messagePattern":"message counter exhausted","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"noiseutil/cipher_state.go","lineNumber":18,"sourceCode":"package noiseutil\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\n\t\"github.com/flynn/noise\"\n)\n\n// RejectHeadroom is the wrap gap for senders racing the counter, sized large enough for any routine count.\nconst RejectHeadroom = uint64(1) << 40\n\n// RejectAfterMessages is the nonce ceiling: encrypting stops RejectHeadroom short of the wrap.\nconst RejectAfterMessages = math.MaxUint64 - RejectHeadroom\n\n// ErrMessageCounterExhausted is returned by EncryptDanger once the nonce reaches RejectAfterMessages.\nvar ErrMessageCounterExhausted = errors.New(\"message counter exhausted\")\n\n// CipherState is the post-handshake AEAD cipher used for the data plane.\n// Each supported cipher has its own concrete implementation in this package with the nonce endianness hardcoded,\n// so the encrypt/decrypt fast path avoids interface dispatch on the byte order.\ntype CipherState interface {\n\t// EncryptDanger encrypts and authenticates a given payload.\n\t//\n\t// out is a destination slice to hold the output of the EncryptDanger operation.\n\t//   - ad is additional data, which will be authenticated and appended to out, but not encrypted.\n\t//   - plaintext is encrypted, authenticated and appended to out.\n\t//   - n is a nonce value which must never be re-used with this key.\n\t//   - nb is a scratch buffer used to assemble the nonce.\n\tEncryptDanger(out, ad, plaintext []byte, n uint64, nb []byte) ([]byte, error)\n\n\t// DecryptDanger authenticates and decrypts a given payload, with the same argument shape as EncryptDanger.\n\tDecryptDanger(out, ad, ciphertext []byte, n uint64, nb []byte) ([]byte, error)\n\n\t// Overhead returns the AEAD tag size, or 0 if the receiver is nil.","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/noiseutil/cipher_state.go#L1-L36","documentation":"EncryptDanger refuses to encrypt once the message nonce reaches RejectAfterMessages (MaxUint64 minus RejectHeadroom of 2^40). Beyond that point the remaining nonce space is reserved for out-of-order receive window headroom, so further encryption would break replay protection; the connection must rekey.","triggerScenarios":"A long-lived tunnel sends more than ~2^64-2^40 messages on the same session key and the nonce counter hits RejectAfterMessages; exercised by TestEncryptRejectsExhaustedCounter.","commonSituations":"Extremely long-lived connections without rekeying, embedded devices that never rotate keys, or test rigs manually passing enormous nonce values.","solutions":["Force a handshake/rekey to establish fresh session keys before the nonce ceiling is reached.","Check that the automatic rekey logic (key reload/rotate timers) is enabled and functioning.","If this appears early in a connection's life, reset the nonce counter to 0 with the new session key."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if n >= noiseutil.RejectAfterMessages {\n    return errors.New(\"nonce ceiling reached; rekey required\")\n}","typeGuard":null,"tryCatchPattern":"out, err := cs.EncryptDanger(out, ad, plaintext, n, nb)\nif errors.Is(err, noiseutil.ErrMessageCounterExhausted) {\n    // initiate new handshake and retry on the fresh session\n}","preventionTips":["Keep automatic rekey enabled and tested.","Monitor session age/nonce usage on long-lived tunnels.","Treat this error as 'must rekey', never retry on the same key."],"tags":["noise","nonce","rekey","replay-protection"],"backgroundTag":"message-counter-exhausted","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"}