cilium/cilium · error

failed to list ipset %s: %w

Error message

failed to list ipset %s: %w

What it means

Returned by ipset.list when the external `ipset list <name>` command exits non-zero (pkg/datapath/iptables/ipset/ipset.go:237). The wrapper error carries the set name and the underlying exec error, so a missing ipset binary, a nonexistent set, or a permission/kernel problem all surface here. In Cilium's reconcile flow (reconcile -> list) this aborts diffing current set members against desired state.

Source

Thrown at pkg/datapath/iptables/ipset/ipset.go:237

	}
	return nil
}

func (i *ipset) remove(ctx context.Context, name string) error {
	if _, err := i.run(ctx, "list", name); err != nil {
		// ipset does not exist, nothing to remove
		return nil
	}
	if _, err := i.run(ctx, "destroy", name); err != nil {
		return fmt.Errorf("failed to remove ipset %s: %w", name, err)
	}
	return nil
}

func (i *ipset) list(ctx context.Context, name string) (AddrSet, error) {
	out, err := i.run(ctx, "list", name)
	if err != nil {
		return AddrSet{}, fmt.Errorf("failed to list ipset %s: %w", name, err)
	}

	addrs := AddrSet{}
	scanner := bufio.NewScanner(bytes.NewReader(out))
	for scanner.Scan() {
		line := scanner.Text()
		addr, err := netip.ParseAddr(line)
		if err != nil {
			continue
		}
		addrs = addrs.Insert(addr)
	}
	if err := scanner.Err(); err != nil {
		return AddrSet{}, fmt.Errorf("failed to scan ipset %s: %w", name, err)
	}
	return addrs, nil
}

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Verify the `ipset` binary exists and works on the host (`ipset --version`) and is present in the agent image
  2. Run the agent as root / with NET_ADMIN capability and confirm `lsmod | grep ip_set` shows the kernel modules
  3. If the set may legitimately not exist, check existence first (or handle the 'does not exist' exit code) before listing, as ipset.remove does
  4. Inspect the wrapped %w error from exec to distinguish binary-not-found vs command failure
  5. Retry the reconcile; Prune re-runs on next startup once the environment is fixed

Example fix

// before
curSet, err := ipset.list(ctx, name)
if err != nil {
    return fmt.Errorf("unable to list ipset %s: %w", name, err)
}
// after: tolerate a not-yet-created set by creating it first (reconcile already does)
if err := ipset.create(ctx, name, string(family)); err != nil {
    return fmt.Errorf("unable to create ipset %s: %w", name, err)
}
curSet, err := ipset.list(ctx, name)
Defensive patterns

Strategy: try-catch

Validate before calling

cmd := exec.Command("ipset", "list", name)
if err := cmd.Run(); err != nil {
    return fmt.Errorf("ipset %s not listable: %w", name, err)
}

Type guard

func isExecNotFound(err error) bool {
    var ee *exec.Error
    return errors.As(err, &ee) && errors.Is(ee.Err, exec.ErrNotFound)
}

Try / catch

curSet, err := ipset.list(ctx, name)
if err != nil {
    var ee *exec.Error
    if errors.As(err, &ee) {
        log.Fatalf("ipset binary missing: %v", err)
    }
    return fmt.Errorf("skipping reconcile of %s: %w", name, err)
}

Prevention

When it happens

Trigger: `ipset list <name>` fails: the ipset executable is missing or not in PATH, the named set does not exist, the caller lacks CAP_NET_ADMIN/root, the kernel ipset module is not loaded, or the command times out / context is canceled.

Common situations: Cilium agent container without ipset binary or NET_ADMIN capability; host kernel without ip_set modules; stale iptables rules referencing a deleted set; tests (TestIPSetListInexistentIPSet) probing a set that was never created.

Related errors


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