JuliusBrussee/caveman · error
envelope: aes
Error message
envelope: aes: %w
What it means
After generating the data key, seal calls aes.NewCipher(dataKey) and wraps any failure as 'envelope: aes: %w'. With a 32-byte key this should always produce AES-256, so the error indicates the cipher could not be constructed — practically only possible if the key length is wrong or the crypto backend is unavailable (e.g. FIPS builds without AES).
Solutions
- Inspect the wrapped cause; confirm the data key is exactly 32 bytes.
- Verify the Go build includes standard AES support (avoid stripped/patched crypto packages).
- Rebuild with the official Go toolchain and retry.
- If on a restricted platform, enable an AES-capable crypto provider.
Defensive patterns
Strategy: try-catch
Try / catch
ciphertext, meta, err := envelope.Seal(plaintext, aad)
if err != nil {
if strings.Contains(err.Error(), "envelope: aes") {
log.Fatalf("AES unavailable in this build — rebuild with standard crypto: %v", err)
}
return err
} Prevention
- Build with the official Go toolchain and unmodified crypto/aes.
- Test envelope sealing at boot (seal/decrypt a canary) to fail fast on crypto issues.
- If FIPS-constrained, verify AES-256 support in the certified provider before deploying.
When it happens
Trigger: Seal/SealForScope reaching aes.NewCipher with a dataKey whose length is not a valid AES key size, or a Go build whose AES implementation is unavailable.
Common situations: Custom/patched crypto stacks (FIPS-restricted builds); toolchain or hardware AES issues; code paths that modified the key material length before sealing.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/1948a73ee19d8f18.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/envelope/envelope.go:76
// SealForScope binds ciphertext authentication to tenant/object scope. Moving
// ciphertext plus metadata to another tenant, project, or object class makes
// decryption fail even when storage and KMS credentials are compromised.
func SealForScope(plaintext []byte, scope Scope) (ciphertext []byte, metaJSON []byte, err error) {
aad, scopeHash, err := scopeAAD(scope)
if err != nil {
return nil, nil, err
}
return seal(plaintext, schemeV2, aad, scopeHash)
}
func seal(plaintext []byte, scheme string, aad []byte, scopeHash string) (ciphertext []byte, metaJSON []byte, err error) {
dataKey := make([]byte, 32)
if _, err := rand.Read(dataKey); err != nil {
return nil, nil, fmt.Errorf("envelope: data key entropy: %w", err)
}
block, err := aes.NewCipher(dataKey)
if err != nil {
return nil, nil, fmt.Errorf("envelope: aes: %w", err)
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, nil, fmt.Errorf("envelope: gcm: %w", err)
}
nonce := make([]byte, gcm.NonceSize())
if _, err := rand.Read(nonce); err != nil {
return nil, nil, fmt.Errorf("envelope: nonce entropy: %w", err)
}
ciphertext = gcm.Seal(nonce, nonce, plaintext, aad)
wrapped, err := secretbox.EncryptPayloadKey(dataKey)
if err != nil {
return nil, nil, fmt.Errorf("envelope: wrap data key: %w", err)
}
meta := Metadata{Scheme: scheme, WrappedDataKey: base64.StdEncoding.EncodeToString(wrapped), ScopeHash: scopeHash}
metaJSON, err = json.Marshal(meta)
if err != nil {View on GitHub (pinned to 3ee70a1026)