cilium/cilium · error

update map %s: %w

Error message

update map %s: %w

What it means

Update() writes a key/value into the underlying ebpf map and wraps any non-nil error from the kernel update call as 'update map %s'. The wrap includes the metric emission via Error2Outcome, meaning this covers any ebpf update failure: map full, invalid key/value size, map closed, or bad flags.

Source

Thrown at pkg/bpf/map_linux.go:1302

			m.updatePressureMetric()
		} else if err == nil {
			m.cache[key.String()] = nil
			m.updatePressureMetric()
		}
	}()

	if err = m.open(); err != nil {
		return err
	}

	err = m.m.Update(key, value, ebpf.UpdateAny)

	if metrics.BPFMapOps.IsEnabled() {
		metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpUpdate, metrics.Error2Outcome(err)).Inc()
	}

	if err != nil {
		return fmt.Errorf("update map %s: %w", m.Name(), err)
	}

	return nil
}

// deleteMapEvent is run at every delete map event.
// If cache is enabled, it will update the cache to reflect the delete.
// As well, if event buffer is enabled, it adds a new event to the buffer.
func (m *Map) deleteMapEvent(key MapKey, err error) {
	m.addToEventsLocked(MapDelete, cacheEntry{
		Key:           key,
		DesiredAction: Delete,
		LastError:     err,
	})
	m.deleteCacheEntry(key, err)
}

func (m *Map) deleteAllMapEvent() {

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Inspect the wrapped cause: increase MaxEntries or switch to LRUHash if the error is 'map full' (ebpf.KeyExists/ENOSPC)
  2. Validate key/value sizes against the MapSpec's KeySize/ValueSize before calling Update
  3. Verify update flags match intent (UpdateAny vs UpdateNoExist/UpdateExist)
  4. Ensure the map is open (not concurrently closed) when Update is invoked

Example fix

// before
spec := &ebpf.MapSpec{Type: ebpf.Hash, MaxEntries: 8}
m.Update(key, val) // update map flows: map full
// after
spec := &ebpf.MapSpec{Type: ebpf.LRUHash, MaxEntries: 65536}
m.Update(key, val)
Defensive patterns

Strategy: try-catch

Validate before calling

if len(kb) != m.KeySize() || len(vb) != m.ValueSize() {
    return fmt.Errorf("key=%d value=%d bytes, map expects %d/%d", len(kb), len(vb), m.KeySize(), m.ValueSize())
}
if m.IsLRU() && m.Len() >= int(m.MaxEntries()) { /* capacity warning */ }

Try / catch

if err := m.Update(key, val); err != nil {
    if errors.Is(err, unix.ENOSPC) || strings.Contains(err.Error(), "map full") {
        return retryWithLRUOrBiggerMap(key, val) // grow MaxEntries / switch to LRUHash
    }
    if errors.Is(err, ebpf.ErrKeyExist) { // wrong flag for intent
        return m.Update(key, val, ebpf.UpdateAny)
    }
    return fmt.Errorf("update map: %w", err)
}

Prevention

When it happens

Trigger: Update() on a full hash/LRU map with ebpf.UpdateNoExist or no LRU eviction capacity; key or value byte length not matching the spec's KeySize/ValueSize; map closed or unpinned concurrently; invalid update flags (e.g. UpdateNoExist on an existing key).

Common situations: MaxEntries too small for workload traffic; struct layout changed (cgo/type mismatch) so marshalled key size no longer matches; LRU map replaced with plain hash causing 'map full'; calling Update after Close during shutdown.

Related errors


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