{"record":{"id":"6c077e88f11359fc","repo":"nats-io/nats-server","slug":"not-enough-nonce-bytes-read-d-d","errorCode":null,"errorMessage":"not enough nonce bytes read (%d != %d)","messagePattern":"not enough nonce bytes read \\((.+?) != (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/filestore.go","lineNumber":929,"sourceCode":"\tconst seedSize = 32\n\tseed = make([]byte, seedSize)\n\tif n, err := rand.Read(seed); err != nil {\n\t\treturn nil, nil, nil, nil, err\n\t} else if n != seedSize {\n\t\treturn nil, nil, nil, nil, fmt.Errorf(\"not enough seed bytes read (%d != %d\", n, seedSize)\n\t}\n\n\taek, err = genEncryptionKey(sc, seed)\n\tif err != nil {\n\t\treturn nil, nil, nil, nil, err\n\t}\n\n\t// Generate our nonce. Use same buffer to hold encrypted seed.\n\tnonce := make([]byte, kek.NonceSize(), kek.NonceSize()+len(seed)+kek.Overhead())\n\tif n, err := rand.Read(nonce); err != nil {\n\t\treturn nil, nil, nil, nil, err\n\t} else if n != len(nonce) {\n\t\treturn nil, nil, nil, nil, fmt.Errorf(\"not enough nonce bytes read (%d != %d)\", n, len(nonce))\n\t}\n\n\tbek, err = genBlockEncryptionKey(sc, seed[:], nonce)\n\tif err != nil {\n\t\treturn nil, nil, nil, nil, err\n\t}\n\n\treturn aek, bek, seed, kek.Seal(nonce, nonce, seed, nil), nil\n}\n\n// Will generate the block encryption key.\nfunc genBlockEncryptionKey(sc StoreCipher, seed, nonce []byte) (cipher.Stream, error) {\n\tif sc == ChaCha {\n\t\treturn chacha20.NewUnauthenticatedCipher(seed, nonce)\n\t} else if sc == AES {\n\t\tblock, err := aes.NewCipher(seed)\n\t\tif err != nil {\n\t\t\treturn nil, err","sourceCodeStart":911,"sourceCodeEnd":947,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/filestore.go#L911-L947","documentation":"Thrown when rand.Read fails to fill the full AEAD nonce buffer (NonceSize bytes) used to encrypt the seed while generating block encryption keys. A short read from crypto/rand indicates a failed system entropy source, so the store aborts key generation rather than reusing/predictable nonces, which would be catastrophic for AES-GCM.","triggerScenarios":"Creating an encrypted file-store stream (genBlockEncryptionKey path) when the kernel entropy source returns fewer bytes than requested without an error.","commonSituations":"Pentesting-style low-entropy VMs, misconfigured containers lacking /dev/urandom or getrandom(2), or heavy concurrent crypto operations on a degraded kernel.","solutions":["Verify the host's entropy/random subsystem (getrandom, /dev/urandom) is functional and restore it","Restart the node and retry the stream creation once entropy is replenished","Run on an environment where crypto/rand is known-good (recent kernel, no blocked syscalls)","Audit sandbox/seccomp rules that might limit getrandom(2)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"nonce := make([]byte, kek.NonceSize())\nif n, err := crypto_rand.Read(nonce); err != nil || n != len(nonce) {\n    return fmt.Errorf(\"entropy source unhealthy: read %d/%d bytes (err=%v)\", n, len(nonce), err)\n}","typeGuard":null,"tryCatchPattern":"// Go: wrap stream creation and fail fast on crypto/rand anomalies\nif err := createEncryptedStream(cfg); err != nil {\n    if strings.Contains(err.Error(), \"not enough\") {\n        // entropy fault: alert ops, do not retry blindly\n    }\n    return err\n}","preventionTips":["Ensure the runtime environment exposes a working getrandom//dev/urandom","Restart the process after entropy subsystem recovery","Audit container security profiles for blocked randomness syscalls","Pin server versions tested against your kernel"],"tags":["crypto","nonce","entropy","filestore"],"backgroundTag":"entropy-short-read","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}