JuliusBrussee/caveman · error
envelope: gcm
Error message
envelope: gcm: %w
What it means
seal constructs an AES-GCM instance with cipher.NewGCM(block) and wraps failure as 'envelope: gcm: %w'. NewGCM only fails if the underlying cipher's block size is nonstandard, so with the library's own AES block this is effectively an internal invariant failure.
Solutions
- Inspect the wrapped cause; confirm crypto/aes is the standard implementation (BlockSize 16).
- Remove any custom crypto replacements/overrides in the build.
- Rebuild with the official Go toolchain and redeploy.
- File a bug with the wrapped error if it persists on a standard build.
Defensive patterns
Strategy: try-catch
Try / catch
ciphertext, meta, err := envelope.Seal(plaintext, aad)
if err != nil {
if strings.Contains(err.Error(), "envelope: gcm") {
log.Fatalf("GCM construction failed — crypto stack invariant broken: %v", err)
}
return err
} Prevention
- Do not vendor-replace crypto/* packages in builds.
- Add a startup self-test that seals and opens a round-trip message.
- Report persistent occurrences on standard builds upstream as bugs.
When it happens
Trigger: Seal/SealForScope calling cipher.NewGCM on a block cipher whose BlockSize() != 16 — not reachable with the standard aes.NewCipher output unless the crypto stack is replaced.
Common situations: Patched or vendor-replaced crypto packages; exotic Go toolchains; test doubles injected in place of crypto/aes.
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/04efe27d8db669b7.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/envelope/envelope.go:80
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 {
return nil, nil, fmt.Errorf("envelope: marshal metadata: %w", err)
}
return ciphertext, metaJSON, nil
}View on GitHub (pinned to 3ee70a1026)