cilium/cilium · error
unable to gob encode: %w
Error message
unable to gob encode: %w
What it means
For event types other than MessageTypeAgent, SendEvent gob-encodes the event into the buffer so listener clients receive gob-encoded payloads. If gob.NewEncoder(&buf).Encode(event) fails, this error wraps the gob error. Gob encoding fails mainly when the value contains types gob cannot handle: unexported fields, channels, funcs, or types not registered with gob for interface values.
Source
Thrown at pkg/monitor/agent/agent.go:175
// marshal notifications into JSON format for legacy listeners
if typ == api.MessageTypeAgent {
msg, ok := event.(api.AgentNotifyMessage)
if !ok {
return errors.New("unexpected event type for MessageTypeAgent")
}
var err error
event, err = msg.ToJSON()
if err != nil {
return fmt.Errorf("unable to JSON encode agent notification: %w", err)
}
}
var buf bytes.Buffer
if err := buf.WriteByte(byte(typ)); err != nil {
return fmt.Errorf("unable to initialize buffer: %w", err)
}
if err := gob.NewEncoder(&buf).Encode(event); err != nil {
return fmt.Errorf("unable to gob encode: %w", err)
}
p := payload.Payload{Data: buf.Bytes(), CPU: 0, Lost: 0, Type: payload.EventSample}
a.sendToListeners(&p)
return nil
}
// hasSubscribersLocked returns true if there are listeners or consumers
// subscribed to the agent right now.
// Note: it is critical to hold the lock for this operation.
func (a *agent) hasSubscribersLocked() bool {
return len(a.listeners)+len(a.consumers) != 0
}
// hasListeners returns true if there are listeners subscribed to the
// agent right now.
func (a *agent) hasListeners() bool {View on GitHub (pinned to ac7b90affa)
Solutions
- Read the wrapped gob error — it names the offending field or missing type registration.
- Register interface concrete types with gob.Register (or gob.RegisterName) before sending.
- Ensure event structs only contain exported, gob-encodable fields; convert chan/func fields to encodable representations.
- Keep payload struct definitions identical (field names/types) between sender and listener to avoid decode-time mismatches, and add a gob round-trip test per event type.
Example fix
// before
type event struct {
ts uint64 // unexported: gob cannot encode
Name string
}
// after
type event struct {
Ts uint64
Name string
}
func init() { gob.Register(event{}) } Defensive patterns
Strategy: validation
Validate before calling
var buf bytes.Buffer
if err := gob.NewEncoder(&buf).Encode(event); err != nil {
logger.Error("event not gob-encodable", "err", err)
return
} // pre-flight encode before handing to SendEvent Type guard
func gobEncodable(v any) bool {
var buf bytes.Buffer
return gob.NewEncoder(&buf).Encode(v) == nil
} Try / catch
err := agent.SendEvent(typ, event)
if err != nil {
var gobErr error
if errors.As(err, &gobErr) && strings.Contains(err.Error(), "gob") {
logger.Error("gob encode failed; check gob.Register for event type", "err", err)
}
} Prevention
- gob.Register every concrete type sent through interface-typed events.
- Use only exported fields in event structs; convert chan/func fields to data.
- Add a gob encode/decode round-trip test per event type.
- Keep event struct definitions in sync between agent and listeners.
When it happens
Trigger: Calling SendEvent(typ, event) with a non-MessageTypeAgent type where event contains unexported fields, chan/func/unsafe.Pointer fields, or an interface value whose concrete type was not registered via gob.Register — causing Encode to error.
Common situations: Adding a struct with unexported fields to an event payload, sending interface-typed events across a new plugin/binary without gob.Register on both sides, or changing a payload type in a way that breaks gob compatibility between writer and reader.
Related errors
- Cannot marshal config: %w
- Cannot marshal nested JSON: %s
- failed to serialize NLRI: %w
- failed to serialize Path Attribute: %w
- failed to serialize Paths: %w
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/6fa83b48601c583b.
Report an issue: GitHub.