nats-io/nats-server · error

not enough seed bytes read (%d != %d

Error message

not enough seed bytes read (%d != %d

What it means

This error is thrown when crypto/rand.Read fills the 32-byte seed buffer with fewer bytes than requested while generating the encryption keys for a file store stream. In Go, crypto/rand.Read is documented to always succeed or return an error, so a short read signals a broken/failed entropy source. The store treats it as unrecoverable and aborts key generation.

Source

Thrown at server/filestore.go:916

	rb, err := fs.prf([]byte(context))
	if err != nil {
		return nil, nil, nil, nil, err
	}

	sc := fs.fcfg.Cipher

	kek, err := genEncryptionKey(sc, rb)
	if err != nil {
		return nil, nil, nil, nil, err
	}
	// Generate random asset encryption key seed.

	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

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Check host entropy health (e.g. /proc/sys/kernel/random/entropy_avail, getrandom availability) and fix the OS/environment issue
  2. Retry the operation once entropy is available; crypto/rand short reads are almost always transient environment faults
  3. Upgrade Go/runtime and OS kernel so crypto/rand.Read behavior matches modern guarantees
  4. Remove any wrappers or LD_PRELOAD interposers that interfere with system randomness

Example fix

// before
if n, err := rand.Read(seed); err != nil {
    return nil, err
} else if n != seedSize {
    return nil, fmt.Errorf("not enough seed bytes read (%d != %d", n, seedSize)
}
// after
// fix the environment first; no code change fixes a failing entropy source.
// At minimum, close the missing paren when logging:
return nil, fmt.Errorf("not enough seed bytes read (%d != %d)", n, seedSize)
Defensive patterns

Strategy: validation

Validate before calling

if n, err := crypto_rand.Read(seed); err != nil || n != len(seed) {
    return fmt.Errorf("entropy source unhealthy: read %d/%d bytes (err=%v)", n, len(seed), err)
}

Try / catch

// Go: check both error and short read
n, err := rand.Read(seed)
if err != nil {
    return fmt.Errorf("rand.Read failed: %w", err)
}
if n != len(seed) {
    return fmt.Errorf("short entropy read: %d != %d", n, len(seed))
}

Prevention

When it happens

Trigger: Calling stream/filestore setup (e.g. creating an encrypted file store via AddStream with a crypto-principalled account) when the OS entropy source fails mid-Read, returning n < 32 without an error.

Common situations: Container/kernel environments with exhausted or blocked getrandom(2), unusual sandboxed VMs, or custom rand.Source replacement hacks on Linux hosts with depleted entropy.

Related errors


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