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

  1. Update to the latest Cilium version — this is usually an internal inconsistency bug; report it with the full wrapped error chain if reproducible.
  2. Do not mutate the CollectionSpec (add/remove/rename programs) concurrently with or via hooks into LoadCollection.
  3. If running a fork with custom pipeline steps, ensure any spec modification happens before computeReachability and that reach is recomputed afterwards.
  4. 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

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


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