crowdsecurity/crowdsec · critical
failed to marshal challenge cookie proto: %w
Error message
failed to marshal challenge cookie proto: %w
What it means
sealCookieV0 serializes the pb.ChallengeCookie envelope with proto.Marshal before encrypting it. This error means protobuf marshaling failed — for a plain generated message like ChallengeCookie, this is essentially unreachable (proto.Marshal only errors on required fields unset or internal wire issues), so it is a defensive internal check.
Source
Thrown at pkg/appsec/challenge/crypto.go:140
block, err := aes.NewCipher(key)
if err != nil {
return "", fmt.Errorf("failed to create cipher: %w", err)
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", fmt.Errorf("failed to create GCM: %w", err)
}
// Reject an over-limit envelope before marshaling it.
maxPlaintext := maxCookieLen/4*3 - 1 - gcm.NonceSize() - gcm.Overhead()
if plaintextLen := cookiePlaintextFixedHeaderLen + len(reason) + proto.Size(envelope); plaintextLen > maxPlaintext {
return "", fmt.Errorf("%w: plaintext=%d > %d", ErrCookieTooLarge, plaintextLen, maxPlaintext)
}
envelopeBytes, err := proto.Marshal(envelope)
if err != nil {
return "", fmt.Errorf("failed to marshal challenge cookie proto: %w", err)
}
nonce := make([]byte, gcm.NonceSize())
if _, err := rand.Read(nonce); err != nil {
return "", fmt.Errorf("failed to generate nonce: %w", err)
}
// Build the plaintext: not_after_be8 || flags || reason_len_be || reason || envelope
plaintext := make([]byte, 0, cookiePlaintextFixedHeaderLen+len(reason)+len(envelopeBytes))
var notAfterBytes [8]byte
binary.BigEndian.PutUint64(notAfterBytes[:], uint64(notAfter))
plaintext = append(plaintext, notAfterBytes[:]...)
plaintext = append(plaintext, flags)
var reasonLenBytes [2]byte
binary.BigEndian.PutUint16(reasonLenBytes[:], uint16(len(reason)))View on GitHub (pinned to 909b515798)
Solutions
- Inspect the wrapped proto error message for the failing field.
- Verify the pb.ChallengeCookie passed to sealCookieV0 is a valid, non-nil generated message.
- Regenerate the pb package if the generated code was hand-edited or is from a mismatched .proto version.
Defensive patterns
Strategy: validation
Validate before calling
if envelope == nil {
return errors.New("nil challenge cookie envelope")
} Type guard
func validEnvelope(e *pb.ChallengeCookie) bool { return e != nil && proto.Size(e) >= 0 } Try / catch
if err != nil {
return fmt.Errorf("proto marshal: %w", err)
} Prevention
- Only pass non-nil generated pb.ChallengeCookie messages.
- Regenerate the pb package when the .proto changes.
- Never hand-edit generated protobuf Go code.
When it happens
Trigger: Calling sealCookieV0 with an envelope that proto.Marshal cannot serialize — practically only with a nil or corrupt generated message, or a message with unpopulated required fields in proto2. All in-repo callers pass a valid &pb.ChallengeCookie{}.
Common situations: Effectively never in supported flows; would require a malformed protobuf type or corrupted reflection state.
Related errors
- failed to create cipher: %w
- failed to create GCM: %w
- ErrCookiePayload
- while encoding request: %w
- appsec datasource requires a hub. this is a bug, please repo
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/56d06c74015def9f.
Report an issue: GitHub.