JuliusBrussee/caveman · error
aes-gcm
Error message
aes-gcm: %w
What it means
cipher.NewGCM(block) wraps the AES block cipher in Galois/Counter Mode. In the Go standard library this call only fails if the underlying block's block size is not 16 bytes, which cannot happen with a successfully constructed aes.Block, so this error is effectively unreachable in practice. It is kept as a defensive wrap in case the block construction or crypto backend changes.
Solutions
- Verify the binary is built against the standard crypto/aes and crypto/cipher packages (check vendoring and replace directives in go.mod).
- Rebuild without custom crypto replacements: go build with a clean module graph.
- Check for any FIPS or custom cipher injection via build tags or init-time package replacement.
- If it persists on the standard toolchain, file an upstream Go issue with go version output.
Example fix
// before: go.mod replace directive swapping crypto internals replace crypto/cipher => ./vendor/fips-cipher // after: use standard library delete the replace directive, then: go mod tidy && go build
Defensive patterns
Strategy: try-catch
Try / catch
out, err := secretbox.Encrypt(pt)
if err != nil {
if strings.HasPrefix(err.Error(), "aes-gcm:") {
// crypto backend invariant broken; escalate, not retryable
log.Fatalf("crypto backend invariant violated: %v", err)
}
return err
} Prevention
- Do not replace or vendor the standard crypto packages.
- Pin and regularly update the Go toolchain; avoid unofficial forks for crypto-sensitive builds.
- Include a startup AES-GCM self-test (encrypt/decrypt a fixed blob) in health checks.
- Keep go.mod free of replace directives touching crypto/*.
When it happens
Trigger: Practically never with the standard crypto/aes block: it would require aes.NewCipher to succeed but return a block whose BlockSize() != 16, e.g. only conceivable with a custom or replaced crypto backend or unusual build (FIPS module mismatch).
Common situations: Almost only seen in exotic environments: patched/regulated crypto builds, vendored crypto replacements, or a bug report worth forwarding upstream. If you see it, the key was fine (it passed aes.NewCipher) and the failure is environmental.
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/d18ec27e183a8100.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/secretbox/secretbox.go:76
if err != nil {
return nil, fmt.Errorf("secretbox: KMS encrypt: %w", err)
}
return wrapped, nil
}
if runtimeenv.IsProduction() {
return nil, fmt.Errorf("secretbox: production requires CAVE_KMS_PROVIDER=scaleway")
}
keyBytes, err := loadKey()
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)
}
nonce := make([]byte, gcm.NonceSize())
if _, err := rand.Read(nonce); err != nil {
return nil, fmt.Errorf("nonce entropy: %w", err)
}
// Seal appends the ciphertext+tag to nonce, so the returned slice is the
// full nonce||ciphertext envelope.
return gcm.Seal(nonce, nonce, plaintext, nil), nil
}
// EncryptPayloadKey wraps an artifact data-encryption key. Production uses the
// dedicated payload KEK; local development retains the same AES-GCM envelope as
// other local secrets.
func EncryptPayloadKey(plaintext []byte) ([]byte, error) {
if useKMS() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
wrapped, err := kms.EncryptPayload(ctx, plaintext)View on GitHub (pinned to 3ee70a1026)