cilium/cilium · error
pruning unused maps: %w
Error message
pruning unused maps: %w
What it means
LoadCollection wraps failures from removeUnusedMaps, which prunes MapSpecs not referenced by any live (reachable) code path, poisoning map loads on dead paths so lazy loading doesn't pull them in. It fails when reachability information is missing (nil, or no entry for a program in the spec). This is the library's dead-map elimination step; a failure means the pruning pass could not run safely.
Source
Thrown at pkg/bpf/collection.go:256
return nil, nil, fmt.Errorf("applying variable overrides: %w", err)
}
reach, err := computeReachability(spec)
if err != nil {
return nil, nil, fmt.Errorf("computing reachability: %w", err)
}
if err := removeUnusedTailcalls(spec, reach, logger); err != nil {
return nil, nil, fmt.Errorf("removing unused tail calls: %w", err)
}
if err := resolveTailCalls(spec); err != nil {
return nil, nil, fmt.Errorf("resolving tail calls: %w", err)
}
fixed := fixedResources(spec, opts.Keep)
if err := removeUnusedMaps(spec, fixed, reach, logger); err != nil {
return nil, nil, fmt.Errorf("pruning unused maps: %w", err)
}
if err := dumpConstants(spec, opts); err != nil {
return nil, nil, fmt.Errorf("writing constants: %w", err)
}
if err := modifyAuxData(spec); err != nil {
return nil, nil, fmt.Errorf("loading auxiliary data: %w", err)
}
// Find and strip all CILIUM_PIN_REPLACE pinning flags before creating the
// Collection. ebpf-go will reject maps with pins it doesn't recognize.
toReplace := consumePinReplace(spec)
if err := patchPrograms(spec, opts.ProgramPatches); err != nil {
return nil, nil, fmt.Errorf("applying program patches: %w", err)
}
View on GitHub (pinned to ac7b90affa)
Solutions
- Update to the latest Cilium version — this is usually an internal inconsistency bug; report it with the full wrapped error chain if reproducible.
- Do not mutate the CollectionSpec (add/remove/rename programs) concurrently with or via hooks into LoadCollection.
- If running a fork with custom pipeline steps, ensure any spec modification happens before computeReachability and that reach is recomputed afterwards.
- Verify opts.Keep entries reference programs/maps that actually exist in the spec.
Example fix
// before: forked pipeline mutates programs after reachability
reach, _ := computeReachability(spec)
spec.Programs["extra_prog"] = customProg // not in reach
removeUnusedMaps(spec, fixed, reach, logger) // pruning unused maps: missing reachability information for program extra_prog
// after: modify spec first, then compute reachability once
spec.Programs["extra_prog"] = customProg
reach, err := computeReachability(spec)
if err != nil { return err }
if err := removeUnusedMaps(spec, fixed, reach, logger); err != nil { return err } Defensive patterns
Strategy: try-catch
Validate before calling
func specProgramsUnchanged(specCopy, orig *ebpf.CollectionSpec) bool {
return len(specCopy.Programs) == len(orig.Programs)
}
// sanity check before load: analysis assumes programs present when computeReachability ran Type guard
func reachabilityCovers(spec *ebpf.CollectionSpec, reach map[string]any) bool {
for name := range spec.Programs {
if _, ok := reach[name]; !ok {
return false
}
}
return true
} Try / catch
if _, _, err := bpf.LoadCollection(logger, spec, opts); err != nil {
if strings.Contains(err.Error(), "pruning unused maps") {
return fmt.Errorf("internal loader inconsistency (missing reachability info); upgrade cilium or report bug: %w", err)
}
return err
} Prevention
- Treat CollectionSpec as read-only after handing it to LoadCollection; the function copies it, so don't mutate concurrently.
- Don't fork the load pipeline; insert spec modifications only before calling LoadCollection.
- Keep Cilium updated — these errors typically indicate internal bugs fixed upstream.
- Capture the full wrapped error chain (%+v) when filing issues; it names the offending program.
When it happens
Trigger: Calling LoadCollection/LoadAndAssign where the internal reachables map is nil, or where removeUnusedMaps iterates spec.Programs and finds a program name with no reachability entry ('missing reachability information for program %s') — e.g. programs added to the spec after computeReachability ran, or a spec mutated between steps.
Common situations: Custom code that adds or replaces programs in the CollectionSpec between LoadCollection's analysis steps (only via internal hooks) or reuses/mutates a spec concurrently while LoadCollection is running on its copy; embedding LoadCollection in a fork with modified pipeline stages; races where the caller mutates spec during load (note: LoadCollection copies the spec, so concurrent mutation of the original is safe — errors arise when the copied spec's programs diverge from reachability results through modified pipeline code).
Related errors
- applying variable overrides: %w
- computing reachability: %w
- missing _aux_cpu_mask variable for .data.aux map
- setting _aux_cpu_mask: %w
- patching %s: %w
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/d1cfe69b286eb95d.
Report an issue: GitHub.