nats-io/nats-server · error

not enough nonce bytes read (%d != %d)

Error message

not enough nonce bytes read (%d != %d)

What it means

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.

Source

Thrown at server/filestore.go:929

	const seedSize = 32
	seed = make([]byte, seedSize)
	if n, err := rand.Read(seed); err != nil {
		return nil, nil, nil, nil, err
	} else if n != seedSize {
		return nil, nil, nil, nil, fmt.Errorf("not enough seed bytes read (%d != %d", n, seedSize)
	}

	aek, err = genEncryptionKey(sc, seed)
	if err != nil {
		return nil, nil, nil, nil, err
	}

	// Generate our nonce. Use same buffer to hold encrypted seed.
	nonce := make([]byte, kek.NonceSize(), kek.NonceSize()+len(seed)+kek.Overhead())
	if n, err := rand.Read(nonce); err != nil {
		return nil, nil, nil, nil, err
	} else if n != len(nonce) {
		return nil, nil, nil, nil, fmt.Errorf("not enough nonce bytes read (%d != %d)", n, len(nonce))
	}

	bek, err = genBlockEncryptionKey(sc, seed[:], nonce)
	if err != nil {
		return nil, nil, nil, nil, err
	}

	return aek, bek, seed, kek.Seal(nonce, nonce, seed, nil), nil
}

// Will generate the block encryption key.
func genBlockEncryptionKey(sc StoreCipher, seed, nonce []byte) (cipher.Stream, error) {
	if sc == ChaCha {
		return chacha20.NewUnauthenticatedCipher(seed, nonce)
	} else if sc == AES {
		block, err := aes.NewCipher(seed)
		if err != nil {
			return nil, err

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Verify the host's entropy/random subsystem (getrandom, /dev/urandom) is functional and restore it
  2. Restart the node and retry the stream creation once entropy is replenished
  3. Run on an environment where crypto/rand is known-good (recent kernel, no blocked syscalls)
  4. Audit sandbox/seccomp rules that might limit getrandom(2)
Defensive patterns

Strategy: validation

Validate before calling

nonce := make([]byte, kek.NonceSize())
if n, err := crypto_rand.Read(nonce); err != nil || n != len(nonce) {
    return fmt.Errorf("entropy source unhealthy: read %d/%d bytes (err=%v)", n, len(nonce), err)
}

Try / catch

// Go: wrap stream creation and fail fast on crypto/rand anomalies
if err := createEncryptedStream(cfg); err != nil {
    if strings.Contains(err.Error(), "not enough") {
        // entropy fault: alert ops, do not retry blindly
    }
    return err
}

Prevention

When it happens

Trigger: Creating an encrypted file-store stream (genBlockEncryptionKey path) when the kernel entropy source returns fewer bytes than requested without an error.

Common situations: Pentesting-style low-entropy VMs, misconfigured containers lacking /dev/urandom or getrandom(2), or heavy concurrent crypto operations on a degraded kernel.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/6c077e88f11359fc. Report an issue: GitHub.