golang/go · error
crypto/cipher: SetNoncePrefixAndMask called twice or after f
Error message
crypto/cipher: SetNoncePrefixAndMask called twice or after first Seal
What it means
Returned by GCMWithXORCounterNonce.SetNoncePrefixAndMask when g.ready is already true, i.e. the method is called a second time, or called after the first Seal (which lazily sets ready if SetNoncePrefixAndMask was skipped). The prefix and mask are immutable for the lifetime of the AEAD so that Seal can enforce a strictly-increasing counter.
Source
Thrown at src/crypto/internal/fips140/aes/gcm/gcm_nonces.go:234
mask uint64
next uint64
}
// SetNoncePrefixAndMask sets the fixed prefix and XOR mask for the nonces used
// in Seal. It must be called before the first call to Seal.
//
// The first 32 bits of nonce are used as the fixed prefix, and the last 64 bits
// are used as the XOR mask.
//
// Note that Seal expects the nonce to be already XOR'd with the mask. The mask
// is provided here only to allow Seal to enforce that the counter is strictly
// increasing.
func (g *GCMWithXORCounterNonce) SetNoncePrefixAndMask(nonce []byte) error {
if len(nonce) != gcmStandardNonceSize {
return errors.New("crypto/cipher: incorrect nonce length given to SetNoncePrefixAndMask")
}
if g.ready {
return errors.New("crypto/cipher: SetNoncePrefixAndMask called twice or after first Seal")
}
g.prefix = byteorder.BEUint32(nonce[:4])
g.mask = byteorder.BEUint64(nonce[4:])
g.ready = true
return nil
}
func (g *GCMWithXORCounterNonce) NonceSize() int { return gcmStandardNonceSize }
func (g *GCMWithXORCounterNonce) Overhead() int { return gcmTagSize }
// Seal implements the [cipher.AEAD] interface, checking that the nonce prefix
// is stable and that the counter is strictly increasing.
//
// It is not safe for concurrent use.
func (g *GCMWithXORCounterNonce) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != gcmStandardNonceSize {
panic("crypto/cipher: incorrect nonce length given to GCM")View on GitHub (pinned to b6b368adc5)
Solutions
- Call SetNoncePrefixAndMask exactly once, before any Seal; prefer NewGCMForQUIC which does both steps atomically.
- Do not reuse/reset the same GCMWithXORCounterNonce across key rotations; construct a new one.
- If you must change prefix/mask, allocate a fresh GCMWithXORCounterNonce via NewGCMForQUIC.
Example fix
// before g, _ := gcm.NewGCMForQUIC(block, iv) g.SetNoncePrefixAndMask(iv) // duplicate -> error // after g, _ := gcm.NewGCMForQUIC(block, iv) // sets prefix+mask exactly once // ... use g.Seal(...) directly
Defensive patterns
Strategy: validation
Validate before calling
// SetNoncePrefixAndMask must be called at most once and only before Seal.
// Track readiness in the caller and refuse to call again.
type nonceInit struct{ done bool }
func (n *nonceInit) init(g *gcm.GCMWithXORCounterNonce, iv []byte) error {
if n.done { return errors.New("nonce already initialized") }
n.done = true
return g.SetNoncePrefixAndMask(iv)
} Type guard
// n/a
Try / catch
if err := g.SetNoncePrefixAndMask(iv); err != nil {
if strings.Contains(err.Error(), "called twice") {
// lifecycle bug: rebuild the AEAD via NewGCMForQUIC instead
}
return err
} Prevention
- Prefer NewGCMForQUIC, which initializes once atomically.
- Treat GCMWithXORCounterNonce as immutable after first Seal.
- Construct a fresh AEAD on key rotation rather than resetting.
When it happens
Trigger: Calling SetNoncePrefixAndMask twice; calling it after Seal has already been invoked (Seal sets g.ready=true on its first call if it was false); constructing via NewGCMForQUIC (which calls it once) and then calling it again externally.
Common situations: Re-initializing the AEAD per-packet instead of constructing once and reusing; copy-paste wiring that calls both NewGCMForQUIC and an explicit SetNoncePrefixAndMask; lifecycle bug where the same GCMWithXORCounterNonce is reset rather than recreated.
Related errors
- crypto/cipher: incorrect nonce length given to SetNoncePrefi
- cipher: incorrect tag size given to GCM
- cipher: the nonce can't have zero length
- cipher: NewGCM requires 128-bit block cipher
- cipher: message authentication failed
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/7385c2d0222c906d.
Report an issue: GitHub.