getsops/sops · critical

Could not generate random bytes for IV: %s

Error message

Could not generate random bytes for IV: %s

What it means

When a fresh IV is needed (the plaintext/additionalData pair is not stashed), Encrypt fills a nonceSize-byte buffer from crypto/rand. rand.Read practically never fails on modern platforms, but if the system entropy source is unavailable the error is wrapped here. Failure points to the operating environment, not the input data.

Source

Thrown at aes/cipher.go:154

		return false
	}
}

// Encrypt takes one of (string, int, float, bool) and encrypts it with the provided key and additional auth data, returning a sops-format encrypted string.
func (c Cipher) Encrypt(plaintext interface{}, key []byte, additionalData string) (ciphertext string, err error) {
	if isEmpty(plaintext) {
		return "", nil
	}
	aescipher, err := cryptoaes.NewCipher(key)
	if err != nil {
		return "", fmt.Errorf("Could not initialize AES GCM encryption cipher: %s", err)
	}
	var iv []byte
	if stash, ok := c.stash[stashKey{plaintext: plaintext, additionalData: additionalData}]; !ok {
		iv = make([]byte, nonceSize)
		_, err = rand.Read(iv)
		if err != nil {
			return "", fmt.Errorf("Could not generate random bytes for IV: %s", err)
		}
	} else {
		iv = stash
	}
	gcm, err := cipher.NewGCMWithNonceSize(aescipher, nonceSize)
	if err != nil {
		return "", fmt.Errorf("Could not create GCM: %s", err)
	}
	var plainBytes []byte
	var encryptedType string
	switch value := plaintext.(type) {
	case string:
		encryptedType = "str"
		plainBytes = []byte(value)
	case int:
		encryptedType = "int"
		plainBytes = []byte(strconv.Itoa(value))
	case float64:

View on GitHub (pinned to 13442bb981)

Solutions

  1. Verify /dev/urandom exists and is readable inside the container/host.
  2. Check the runtime sandbox (seccomp/AppArmor) permits getrandom(2) or read(2) on urandom.
  3. Retry after the system recovers; entropy exhaustion is usually transient.

Example fix

// before (sandbox blocks getrandom)
// seccomp profile: no getrandom
// after
// add getrandom to the seccomp allowlist, then:
cipher.Encrypt(value, key, ad)
Defensive patterns

Strategy: retry

Validate before calling

if _, err := os.Stat("/dev/urandom"); err != nil {
    return fmt.Errorf("entropy source unavailable: %w", err)
}

Try / catch

ciphertext, err := cipher.Encrypt(v, key, ad)
if err != nil && strings.Contains(err.Error(), "random bytes") {
    time.Sleep(100 * time.Millisecond)
    return retryEncrypt(v, key, ad) // bounded retries
}

Prevention

When it happens

Trigger: Calling Cipher.Encrypt when the crypto/rand reader cannot provide nonceSize (32) random bytes — e.g. /dev/urandom unavailable, severe resource exhaustion, or a restricted sandbox/blocking seccomp profile.

Common situations: Containers with stripped-down /dev or restricted syscall allowlists; embedded/minimal images lacking a usable entropy source; sandboxed CI runners blocking getrandom(2).

Related errors


AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01). Data as JSON: /api/errors/576d8b6fe28277e2. Report an issue: GitHub.