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
- Verify /dev/urandom exists and is readable inside the container/host.
- Check the runtime sandbox (seccomp/AppArmor) permits getrandom(2) or read(2) on urandom.
- 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
- Ensure /dev/urandom is mounted in containers
- Keep getrandom(2) in seccomp allowlists
- Avoid running crypto workloads on hosts with exhausted entropy
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
- Could not initialize AES GCM encryption cipher: %s
- Could not create GCM: %s
- Error marshaling timestamp %q: %w
- Value to encrypt has unsupported type %T
- Unknown datatype: %s
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/576d8b6fe28277e2.
Report an issue: GitHub.