cilium/cilium · error

get next program: %w

Error message

get next program: %w

What it means

The BPF metrics collector's Usage() enumerates all loaded BPF programs by walking ebpf.ProgramGetNextID() starting from ID 0. If fetching the next program ID fails with anything other than os.ErrNotExist (the normal end-of-iteration signal), the walk aborts with this wrapped error. It means the program ID enumeration itself failed, not any specific program.

Source

Thrown at pkg/metrics/bpf.go:72

	progPrefixes []string

	programsVisited map[ebpf.ProgramID]struct{}
	mapsVisited     map[ebpf.MapID]struct{}
}

// Usage returns the memory usage of all BPF programs matching the filter
// specified in the constructor, as well as the memory usage of all maps
// associated with those programs.
func (v *bpfVisitor) Usage() (_ *bpfUsage, err error) {
	var id ebpf.ProgramID
	for {
		id, err = ebpf.ProgramGetNextID(id)
		if errors.Is(err, os.ErrNotExist) {
			break
		}
		if err != nil {
			return nil, fmt.Errorf("get next program: %w", err)
		}

		if err := v.visitProgram(id, v.progPrefixes); err != nil {
			return nil, fmt.Errorf("check program %d: %w", id, err)
		}
	}

	return &v.bpfUsage, nil
}

// visitProgram opens the given program by id and collects its memory usage and
// that of all maps it uses.
//
// If prefixes are specified, the program is only checked if its name starts
// with one of the prefixes. This is useful to omit programs that are not
// relevant for the caller.
func (v *bpfVisitor) visitProgram(id ebpf.ProgramID, prefixes []string) error {
	if _, ok := v.programsVisited[id]; ok {

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Grant CAP_BPF (and CAP_SYS_ADMIN on older kernels) to the process collecting metrics
  2. Check kernel version >= 4.13 for program ID iteration support
  3. Inspect the wrapped root error to identify syscall denial (EPERM/ENOSYS) and adjust LSM/seccomp policy accordingly
  4. Verify the bpf filesystem is mounted for ID enumeration
Defensive patterns

Strategy: validation

Validate before calling

// Verify BPF iteration is permitted before collecting metrics
if _, err := ebpf.ProgramGetNextID(0); err != nil && !errors.Is(err, os.ErrNotExist) {
    if errors.Is(err, os.ErrPermission) {
        return errors.New("need CAP_BPF to enumerate BPF programs")
    }
    return fmt.Errorf("program ID enumeration unavailable: %w", err)
}

Try / catch

// Go: classify the enumeration failure
usage, err := v.Usage()
if err != nil {
    var permErr syscall.Errno
    if errors.As(err, &permErr) && permErr == syscall.EPERM {
        // degrade metrics instead of hard-failing the scrape
    }
    return err
}

Prevention

When it happens

Trigger: Calling Usage() (metrics collection) on a system where ProgramGetNextID returns an unexpected error — e.g. missing privileges to iterate BPF objects, kernel without BPF program iteration support (pre-4.13 kernels), or bpf() syscall denials by LSM/seccomp policy.

Common situations: Running the metrics endpoint in an unprivileged container lacking CAP_BPF; hardened environments where seccomp blocks BPF commands; old kernels predating BPF ID enumeration.

Related errors


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