cilium/cilium · error

failed to convert SubscriberV4InnerMap FD to *ebpf.Map: %w

Error message

failed to convert SubscriberV4InnerMap FD to *ebpf.Map: %w

What it means

After finding the group's value (a struct holding an inner-map FD), Lookup converts that FD back to an *ebpf.Map with ebpf.MapFromID. This error is returned when the FD is stale, invalid, or does not refer to an existing map. It means the outer map's value references an inner map that no longer exists.

Source

Thrown at pkg/maps/multicast/subscribermap.go:175

	var val GroupV4Val

	key, err := NewGroupV4KeyFromNetIPAddr(group)
	if err != nil {
		return nil, err
	}

	err = m.Map.Lookup(key.Group, &val)
	if errors.Is(err, ebpf.ErrKeyNotExist) {
		return nil, fmt.Errorf("multicast group %s does not exist: %w", group.String(), err)
	}
	if err != nil {
		return nil, fmt.Errorf("failed to query for multicast group: %w", err)
	}

	var subMap *ebpf.Map
	subMap, err = ebpf.MapFromID(m.logger, int(val.FD))
	if err != nil {
		return nil, fmt.Errorf("failed to convert SubscriberV4InnerMap FD to *ebpf.Map: %w", err)
	}

	return &SubscriberV4InnerMap{subMap}, nil
}

func (m GroupV4OuterMap) Delete(group netip.Addr) error {
	key, err := NewGroupV4KeyFromNetIPAddr(group)
	if err != nil {
		return err
	}
	return m.Map.Delete(key)
}

// List returns a list of all multicast groups in the map. Batch lookup is used to get the groups if supported.
// Batch lookup is supported in kernel version 5.19 and later for map.HashOfMaps
func (m GroupV4OuterMap) List() ([]netip.Addr, error) {
	if m.batchLookupSupported {
		return m.ListBatch()

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Retry the Lookup; if it persists, Delete and re-create the group entry so a fresh inner map FD is stored
  2. Check for concurrent Delete/Insert on the same group and serialize access
  3. Inspect `bpftool map list` to confirm the inner map ID still exists
  4. Ensure agent shutdown ordering does not close inner maps before in-flight lookups complete

Example fix

// before
subMap, err = ebpf.MapFromID(m.logger, int(val.FD))
if err != nil {
    return nil, fmt.Errorf("failed to convert SubscriberV4InnerMap FD to *ebpf.Map: %w", err)
}
// after
subMap, err = ebpf.MapFromID(m.logger, int(val.FD))
if err != nil {
    // stale inner-map FD: recreate the group entry
    if derr := m.Delete(group); derr != nil { return nil, derr }
    return nil, fmt.Errorf("stale inner map FD for group %s: %w", group, err)
}
Defensive patterns

Strategy: retry

Try / catch

subMap, err := outerMap.Lookup(group)
if err != nil {
    if isStaleFD(err) {
        if derr := outerMap.Delete(group); derr == nil {
            return outerMap.Lookup(group) // recreate path
        }
    }
    return err
}

Prevention

When it happens

Trigger: val.FD holds an invalid or closed FD when ebpf.MapFromID(m.logger, int(val.FD)) is called, e.g. inner map deleted between lookup and conversion, or corrupted/stale FD stored in the outer map entry.

Common situations: Race with Delete of the group removing the inner map while another goroutine looks it up; FD reuse/corruption; agent teardown closed inner maps while lookups still in flight.

Related errors


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