golang/go · error
cipher: incorrect tag size given to GCM
Error message
cipher: incorrect tag size given to GCM
What it means
Returned by gcm.New (the FIPS-140 AES-GCM constructor) when tagSize is outside [gcmMinimumTagSize, gcmBlockSize] = [12, 16]. NIST SP 800-38D requires tags of at least 12 bytes, and GCM's tag can be at most the 16-byte block size. This surfaces through cipher.NewGCMWithNonceSize/cipher.NewGCMWithTagSize in crypto/cipher.
Source
Thrown at src/crypto/internal/fips140/aes/gcm/gcm.go:33
type GCM struct {
cipher aes.Block
nonceSize int
tagSize int
gcmPlatformData
}
func New(cipher *aes.Block, nonceSize, tagSize int) (*GCM, error) {
// This function is outlined to let the allocation happen on the parent stack.
return newGCM(&GCM{}, cipher, nonceSize, tagSize)
}
// newGCM is marked go:noinline to avoid it inlining into New, and making New
// too complex to inline itself.
//
//go:noinline
func newGCM(g *GCM, cipher *aes.Block, nonceSize, tagSize int) (*GCM, error) {
if tagSize < gcmMinimumTagSize || tagSize > gcmBlockSize {
return nil, errors.New("cipher: incorrect tag size given to GCM")
}
if nonceSize <= 0 {
return nil, errors.New("cipher: the nonce can't have zero length")
}
if cipher.BlockSize() != gcmBlockSize {
return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
}
g.cipher = *cipher
g.nonceSize = nonceSize
g.tagSize = tagSize
initGCM(g)
return g, nil
}
const (
gcmBlockSize = 16
gcmTagSize = 16
gcmMinimumTagSize = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.View on GitHub (pinned to b6b368adc5)
Solutions
- Use tagSize in {12,13,14,15,16}; prefer the default 16 unless you have a protocol constraint.
- If omitted, omit the option entirely so the default gcmTagSize (16) applies.
- Validate user-supplied tag size against [12,16] before constructing the AEAD.
Example fix
// before aead, err := cipher.NewGCM(block, cipher.WithTagSize(8)) // after aead, err := cipher.NewGCM(block) // default 16-byte tag // or explicit: aead, err := cipher.NewGCM(block, cipher.WithTagSize(16))
Defensive patterns
Strategy: validation
Validate before calling
func validGCMTagSize(n int) bool { return n >= 12 && n <= 16 }
// usage
if !validGCMTagSize(tagSize) { return errors.New("tag size must be 12..16") }
aead, err := cipher.NewGCM(block, cipher.WithTagSize(tagSize)) Type guard
// n/a: int parameter; guard with range check.
Try / catch
aead, err := cipher.NewGCM(block, cipher.WithTagSize(tagSize))
if err != nil { return fmt.Errorf("gcm init: %w", err) } Prevention
- Default to the 16-byte tag; only deviate for a documented protocol constraint.
- Validate user-supplied tag sizes against [12,16].
- Unit-test the constructor with boundary values.
When it happens
Trigger: Calling cipher.NewGCM(block, cipher.WithTagSize(n)) or gcm.New(block, nonceSize, tagSize) with tagSize < 12 or > 16.
Common situations: Passing tagSize=0 (default int) by mistake; computing tag size from a config value that can be 8 or 32; copying a non-GCM tag length from another AEAD (e.g. Poly1305's 16 is fine, but ChaCha's defaults misremembered as 8).
Related errors
- cipher: the nonce can't have zero length
- cipher: NewGCM requires 128-bit block cipher
- crypto/cipher: incorrect nonce length given to SetNoncePrefi
- crypto/aes: GCM tag and nonce sizes can't be non-standard at
- cipher: message authentication failed
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/cd60af36fc9f8684.
Report an issue: GitHub.