cilium/cilium · error
program %s is nil
Error message
program %s is nil
What it means
attachXDPProgram validates that the ebpf.Program handle for progName is non-nil before attaching. Cilium throws 'program %s is nil' when the collection/spec did not contain the expected named program, so attaching cannot proceed. This is a defensive check against loading a datapath object that lacks the required XDP program symbol.
Source
Thrown at pkg/datapath/loader/xdp.go:301
}
if err != nil {
return fmt.Errorf("attaching XDP program: %w", err)
}
if err := commit(); err != nil {
return fmt.Errorf("committing bpf pins: %w", err)
}
return nil
}
// attachXDPProgram attaches prog with the given progName to link.
//
// bpffsDir should exist and point to the links/ subdirectory in the per-device
// bpffs directory.
func attachXDPProgram(logger *slog.Logger, iface netlink.Link, prog *ebpf.Program, progName, bpffsDir string, flags link.XDPAttachFlags) error {
if prog == nil {
return fmt.Errorf("program %s is nil", progName)
}
// Attempt to open and update an existing link.
pin := filepath.Join(bpffsDir, progName)
err := bpf.UpdateLink(pin, prog)
switch {
// Update successful, nothing left to do.
case err == nil:
logger.Info("Updated link for program",
logfields.Link, pin,
logfields.ProgName, progName,
)
return nil
// Link exists, but is defunct, and needs to be recreated. The program
// no longer gets triggered at this point and the link needs to be removed
// to proceed.View on GitHub (pinned to ac7b90affa)
Solutions
- Verify the compiled ELF contains progName (llvm-objdump -h / bpftool prog) and recompile the datapath
- Ensure Cilium image and node bpf sources are from the same version; wipe /var/run/cilium/state and restart
- Check the loader was handed the correct object path for XDP (not the generic bpf.o)
- If integrating programmatically, confirm the collection map key/program name matches the ELF symbol
Example fix
// before
prog := coll.Programs[progName]
err := attachXDPProgram(logger, iface, prog, progName, dir, flags)
// after
prog, ok := coll.Programs[progName]
if !ok || prog == nil {
return fmt.Errorf("collection %s lacks program %s; recompile datapath", objPath, progName)
}
err := attachXDPProgram(logger, iface, prog, progName, dir, flags) Defensive patterns
Strategy: type-guard
Validate before calling
// after loading the collection
prog, ok := coll.Programs[progName]
if !ok || prog == nil {
return fmt.Errorf("program %s missing from %s", progName, objPath)
} Type guard
func programExists(coll *ebpf.Collection, name string) (*ebpf.Program, bool) {
if coll == nil { return nil, false }
p, ok := coll.Programs[name]
return p, ok && p != nil
} Try / catch
// Go: guard before attach
if prog == nil {
return fmt.Errorf("cannot attach: program %s not loaded; recompile datapath", progName)
} Prevention
- Recompile and reload the datapath together with every Cilium image upgrade
- Validate the compiled object contains expected program names in CI (bpftool/llvm-objdump)
- Keep bpf sources and agent binaries in the same container image
- Never hand-edit or partially copy datapath object files
When it happens
Trigger: spec/collection lookup for progName (e.g. the XDP entrypoint program) yields nil because the compiled object's program name changed, the ELF was built from wrong source files, or the wrong object was compiled/loaded.
Common situations: Mistmatched bpf_xdp.c source and expected program name after a Cilium upgrade; build script compiling the wrong .o; datapath source-tree/bpf objects out of sync between cilium image and node state.
Related errors
- loading program: %w
- running probe: %w
- loading eBPF ELF %s: %w
- attaching XDP program: %w
- committing bpf pins: %w
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/b870cc537ecf1483.
Report an issue: GitHub.