cilium/cilium · error
ErrMapNotOpened
ErrMapNotOpened
Error message
%s: %w
What it means
BatchLookup is a method on the Map's iterator access path that requires the underlying ebpf map to be open. The read lock is taken to guard against concurrent Close(), and if m.m is nil — the map was never opened or was closed concurrently — the sentinel error ErrMapNotOpened wrapped with the map name is returned.
Source
Thrown at pkg/bpf/map_linux.go:1203
if err := m.DumpWithCallback(callback); err != nil {
return err
}
return nil
}
// BatchLookup returns the count of elements in the map by dumping the map
// using batch lookup.
func (m *Map) BatchLookup(cursor *ebpf.MapBatchCursor, keysOut, valuesOut any, opts *ebpf.BatchOptions) (int, error) {
// Hold the read lock for the duration of the batch lookup so that a
// concurrent Close() (which takes the write lock and sets m.m to nil)
// cannot yank the underlying map out from under us mid-iteration.
m.lock.RLock()
defer m.lock.RUnlock()
if m.m == nil {
return 0, fmt.Errorf("%s: %w", m.name, ErrMapNotOpened)
}
return m.m.BatchLookup(cursor, keysOut, valuesOut, opts)
}
// DumpIfExists dumps the contents of the map into hash via Dump() if the map
// file exists
func (m *Map) DumpIfExists(hash map[string][]string) error {
found, err := m.exist()
if err != nil {
return err
}
if found {
return m.Dump(hash)
}
return nilView on GitHub (pinned to ac7b90affa)
Solutions
- Call Open() (or OpenOrCreate()) successfully before any BatchLookup use
- Use errors.Is(err, bpf.ErrMapNotOpened) to detect this case and open the map lazily, then retry
- Serialize Close against iteration via context cancellation or the library's locking conventions
- Check startup logs for earlier open failures so the map is not silently left unopened
Example fix
// before
n, err := m.BatchLookup(cursor, keys, vals, nil) // mymap: map not opened
// after
if err := m.Open(); err != nil { return err }
n, err := m.BatchLookup(cursor, keys, vals, nil)
if errors.Is(err, bpf.ErrMapNotOpened) { _ = m.Open(); /* retry */ } Defensive patterns
Strategy: type-guard
Validate before calling
func ensureOpen(m *bpf.Map) error {
if !m.IsOpen() { return m.Open() } // or equivalent check before batch lookups
return nil
} Type guard
func isOpen(m *bpf.Map) bool { return m != nil && m.IsOpen() } Try / catch
n, err := m.BatchLookup(cursor, keys, vals, nil)
if errors.Is(err, bpf.ErrMapNotOpened) {
if oerr := m.Open(); oerr != nil { return oerr }
n, err = m.BatchLookup(cursor, keys, vals, nil) // retry once
}
if err != nil { return err } Prevention
- Always Open()/OpenOrCreate() before BatchLookup
- Cancel iteration via context before Close during shutdown
- Treat ErrMapNotOpened as recoverable: open and retry once
- Surface early open failures so maps are never silently unopened
When it happens
Trigger: Calling BatchLookup before Open()/OpenOrCreate() on the Map, or after another goroutine called Close(), or after a failed open left m.m nil.
Common situations: Skipping the Open step in a fast-path code path that assumed the map was always open; shutdown ordering where Close runs while iteration is still in flight; open failure earlier in startup ignored and later calls hit the nil map.
Related errors
- registry has already been started
- registry has not yet been started
- opening XDP program id %d: %w
- attaching prog to /dev/null did not result in error
- not supported
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/5d7367ecbaa02f86.
Report an issue: GitHub.