netbirdio/netbird · error
clear and delete chain %s in table %s: %w
Error message
clear and delete chain %s in table %s: %w
What it means
Returned by router.cleanUpDefaultForwardRules when iptablesClient.ClearAndDeleteChain fails for an existing NetBird chain (flush + delete). The comment in the source names the classic cause: deleting a chain that is still referenced fails with 'device or resource busy'. The code removes its own jump rules first precisely to avoid this, so a failure means some other reference remains.
Source
Thrown at client/firewall/iptables/router_linux.go:431
for _, chainInfo := range []struct {
chain string
table string
}{
{chainRTFWDIN, tableFilter},
{chainRTFWDOUT, tableFilter},
{chainRTPRE, tableMangle},
{chainRTNAT, tableNat},
{chainRTRDR, tableNat},
{chainNATOutput, tableNat},
{chainRTMSSCLAMP, tableMangle},
} {
ok, err := r.iptablesClient.ChainExists(chainInfo.table, chainInfo.chain)
if err != nil {
return fmt.Errorf("check chain %s in table %s: %w", chainInfo.chain, chainInfo.table, err)
} else if ok {
if err = r.iptablesClient.ClearAndDeleteChain(chainInfo.table, chainInfo.chain); err != nil {
return fmt.Errorf("clear and delete chain %s in table %s: %w", chainInfo.chain, chainInfo.table, err)
}
}
}
return nil
}
func (r *router) createContainers() error {
for _, chainInfo := range []struct {
chain string
table string
}{
{chainRTFWDIN, tableFilter},
{chainRTFWDOUT, tableFilter},
{chainRTPRE, tableMangle},
{chainRTNAT, tableNat},
{chainRTRDR, tableNat},
{chainRTMSSCLAMP, tableMangle},View on GitHub (pinned to 93e97f4bf1)
Solutions
- List references: sudo iptables-save | grep -e '-j NETBIRD-' and delete the foreign/stale jumps
- Retry cleanup once references are gone
- Ensure a single netbird instance runs per host
- If busy persists, flush manually: sudo iptables -F <chain> && sudo iptables -X <chain> per table
Example fix
# manual recovery when agent cleanup keeps failing sudo iptables-save | grep -- '-j NETBIRD-' sudo iptables -t nat -D OUTPUT -j NETBIRD-NAT-OUTPUT 2>/dev/null sudo iptables -F NETBIRD-RT-NAT && sudo iptables -X NETBIRD-RT-NAT
Defensive patterns
Strategy: validation
Validate before calling
// before deleting, confirm nothing jumps into the chain
out, _ := exec.Command("iptables-save").Output()
for _, line := range strings.Split(string(out), "\n") {
if strings.Contains(line, "-j "+chain) {
return fmt.Errorf("chain %s still referenced: %s", chain, line)
}
} Try / catch
if err = r.iptablesClient.ClearAndDeleteChain(chainInfo.table, chainInfo.chain); err != nil {
if strings.Contains(err.Error(), "busy") || strings.Contains(err.Error(), "Resource busy") {
// sweep foreign jump rules, then retry this chain once
}
return fmt.Errorf("clear and delete chain %s in table %s: %w", chainInfo.chain, chainInfo.table, err)
} Prevention
- Always remove jump rules from built-in chains before deleting custom chains
- Search 'iptables-save | grep -e "-j NETBIRD-"' after upgrade migrations
- Keep one agent instance; concurrent re-adds of jumps cause busy deletes
When it happens
Trigger: Init cleanup or Reset flushing one of the seven custom chains while something still jumps to it: a rule added by another tool or an older netbird version, a second NETBIRD chain referencing it, or a concurrent agent re-adding jumps between the jump cleanup and the chain delete.
Common situations: Upgrade from an older agent layout whose jump specs differ (so DeleteIfExists did not match); leftover hand-written rules targeting NETBIRD-* chains; two agents racing on one host.
Related errors
- destroy set %s: %w
- remove nat rule: %w
- remove inverse nat rule: %w
- remove legacy routing rule: %w
- remove legacy forwarding rule %s -> %s: %v
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/ae099a1d8e26768c.
Report an issue: GitHub.