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

  1. Read the wrapped gob error — it names the offending field or missing type registration.
  2. Register interface concrete types with gob.Register (or gob.RegisterName) before sending.
  3. Ensure event structs only contain exported, gob-encodable fields; convert chan/func fields to encodable representations.
  4. 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

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


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/6fa83b48601c583b. Report an issue: GitHub.