JuliusBrussee/caveman · error
aes-gcm open
Error message
aes-gcm open: %w
What it means
AES-GCM Open failed to authenticate/decrypt the envelope: the nonce was extracted but the ciphertext did not verify under the configured key. GCM is an AEAD, so any key mismatch, tampering, or corruption causes Open to return an error, which secretbox wraps as "aes-gcm open: ...". This is the standard failure when the wrong key is configured or the ciphertext was modified.
Solutions
- Confirm the decryption-side key (e.g. SECRETBOX_KEY env) is byte-identical to the key used to encrypt; re-export it and retry.
- Re-encrypt the secret with the current key and replace the stored ciphertext instead of trying to fix it.
- Check whether the ciphertext was modified in transit/storage (compare checksums or re-copy the base64 blob verbatim).
- If keys were rotated, decrypt with the old key and re-encrypt with the new one; keep old keys available during rotation windows.
Example fix
// before (mismatched key picked up from shell profile)
export SECRETBOX_KEY="stale-key"
plain, err := secretbox.ResolveEnvironmentSecret("", "APP_SECRET") // aes-gcm open: cipher: message authentication failed
// after (fail fast on key mismatch)
if os.Getenv("SECRETBOX_KEY") != expectedKeyFingerprint {
return fmt.Errorf("SECRETBOX_KEY does not match the key this secret was encrypted with")
}
plain, err := secretbox.ResolveEnvironmentSecret("", "APP_SECRET") Defensive patterns
Strategy: try-catch
Validate before calling
// compare key fingerprints without revealing the key
if sha256.Sum256([]byte(os.Getenv("SECRETBOX_KEY"))) != expectedKeySum {
return fmt.Errorf("SECRETBOX_KEY fingerprint mismatch for this environment")
} Try / catch
plain, err := secretbox.Decrypt(envelope)
if err != nil {
var authFail = strings.Contains(err.Error(), "aes-gcm open")
if authFail {
return fmt.Errorf("ciphertext cannot be decrypted with the configured key; check rotation: %w", err)
}
return err
} Prevention
- Keep encryption and decryption keys in lockstep; rotate by re-encrypting, not just swapping keys.
- Never hand-edit base64 ciphertext; regenerate via Encrypt.
- Label ciphertext with a key ID/version so mismatches are diagnosable.
- Copy ciphertext values verbatim (no clipboard normalization).
When it happens
Trigger: Decrypt (or ResolveEnvironmentSecret after base64 decode) receives a well-formed, correctly sized envelope whose ciphertext, nonce, or key differs from the one used at encryption time — wrong key in the environment, edited ciphertext, or bytes re-encoded lossily (e.g. latin-1 instead of base64).
Common situations: Rotating SECRETBOX_KEY in one environment but not the one decrypting; the encrypted value was hand-edited or copy-pasted with a dropped character; two services share an env var name but different keys; a config store trimmed/normalized the value.
Related errors
- ciphertext too short
- aes-gcm
- envelope: ciphertext too short
- envelope: gcm
- envelope: object kind is required
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/9600638a0a00027c.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/secretbox/secretbox.go:137
if err != nil {
return nil, err
}
block, err := aes.NewCipher(keyBytes)
if err != nil {
return nil, fmt.Errorf("aes cipher: %w", err)
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, fmt.Errorf("aes-gcm: %w", err)
}
ns := gcm.NonceSize()
if len(envelope) < ns {
return nil, fmt.Errorf("ciphertext too short")
}
nonce, ct := envelope[:ns], envelope[ns:]
plain, err := gcm.Open(nil, nonce, ct, nil)
if err != nil {
return nil, fmt.Errorf("aes-gcm open: %w", err)
}
return plain, nil
}
// DecryptPayloadKey unwraps an artifact data-encryption key. KMS envelopes are
// restricted to the configured payload key plus the explicit legacy secrets
// key used before key separation.
func DecryptPayloadKey(envelope []byte) ([]byte, error) {
if kms.IsEnvelope(envelope) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
plaintext, err := kms.DecryptPayload(ctx, envelope)
if err != nil {
return nil, fmt.Errorf("secretbox: payload KMS decrypt: %w", err)
}
return plaintext, nil
}
return Decrypt(envelope)View on GitHub (pinned to 3ee70a1026)