tailscale/tailscale · error
get input chain: %w
Error message
get input chain: %w
What it means
AddLoopbackRule needs the standard "input" chain of the address family's filter table and this error means getChainFromTable couldn't get it. Two distinct causes share this wrap: errorChainNotFound ('chain input not found in table filter') when the base chains were never created — the doc for newNfTablesRunner explicitly says it does NOT guarantee tables/chains exist — or the underlying 'list chains' netlink failure. Callers that skipped base setup hit the first; broken environments the second.
Source
Thrown at util/linuxfw/nftables_runner.go:876
return nil, fmt.Errorf("nftables for IPv6 are not available on this host")
}
if addr.Is6() {
return n.nft6, nil
}
return n.nft4, nil
}
// AddLoopbackRule adds an nftables rule to permit loopback traffic to
// a local Tailscale IP. This rule is added only if it does not already exist.
func (n *nftablesRunner) AddLoopbackRule(addr netip.Addr) error {
nf, err := n.getNFTByAddr(addr)
if err != nil {
return fmt.Errorf("error setting up nftables for IP family of %v: %w", addr, err)
}
inputChain, err := getChainFromTable(n.conn, nf.Filter, chainNameInput)
if err != nil {
return fmt.Errorf("get input chain: %w", err)
}
if err := insertLoopbackRule(n.conn, nf.Proto, nf.Filter, inputChain, addr); err != nil {
return fmt.Errorf("add loopback rule: %w", err)
}
return nil
}
// DelLoopbackRule removes the nftables rule permitting loopback
// traffic to a Tailscale IP.
func (n *nftablesRunner) DelLoopbackRule(addr netip.Addr) error {
nf, err := n.getNFTByAddr(addr)
if err != nil {
return fmt.Errorf("error setting up nftables for IP family of %v: %w", addr, err)
}
inputChain, err := getChainFromTable(n.conn, nf.Filter, chainNameInput)View on GitHub (pinned to 6e0912f979)
Solutions
- Call the runner's base setup (EnsureBase) before AddLoopbackRule — it creates the filter table chains this API depends on.
- Verify the chain exists: `nft list table ip filter` should show chain input.
- If the error chain is the netlink one (wrapped errno), fix capabilities/kernel support as for the 'list chains' error.
- Re-run the operation after restoring the table; AddLoopbackRule is idempotent.
Example fix
// before
err := fw.AddLoopbackRule(addr) // get input chain: chain input not found in table filter
// after
if err := fw.EnsureBase(); err != nil { // creates filter table + input chain etc.
return err
}
err := fw.AddLoopbackRule(addr) Defensive patterns
Strategy: validation
Validate before calling
if err := fw.EnsureBase(); err != nil { // creates filter table + input chain
return err
}
// now AddLoopbackRule cannot hit 'chain input not found' Type guard
func isChainNotFound(err error) bool {
return err != nil && strings.Contains(err.Error(), "not found in table")
} Try / catch
err := fw.AddLoopbackRule(addr)
if isChainNotFound(err) {
// base chains absent: run EnsureBase once and retry
if berr := fw.EnsureBase(); berr != nil {
return berr
}
err = fw.AddLoopbackRule(addr)
} Prevention
- Always call EnsureBase (or the runner's setup path) before loopback-rule APIs on a fresh runner.
- Monitor for external tools flushing the filter table while tailscaled runs.
- Treat 'not found in table' inside these wraps as an initialization-order signal, not corruption.
When it happens
Trigger: Calling AddLoopbackRule on a runner whose EnsureBase/chain provisioning never ran (chains missing from the filter table), on a host whose filter table or input chain was flushed/deleted by another program, or when the netlink chain listing fails (permissions/kernel support).
Common situations: Code using linuxfw.New + AddLoopbackRule without EnsureBase; external tools (nft flush ruleset, docker, firewalld reload) removing the input chain mid-run; unprivileged processes failing at the netlink dump.
Related errors
AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18).
Data as JSON: /api/errors/10c803553e05f8fe.
Report an issue: GitHub.