tailscale/tailscale · error
create forward chain: %w
Error message
create forward chain: %w
What it means
AddChains failed to create the ts-forward regular chain inside the filter table (createChainIfNotExist). It fires when the chain-creation netlink message fails — often because the table state changed concurrently or the operation was rejected by the kernel.
Source
Thrown at util/linuxfw/nftables_runner.go:945
}
// AddChains creates custom Tailscale chains in netfilter via nftables
// if the ts-chain doesn't already exist.
func (n *nftablesRunner) AddChains() error {
polAccept := nftables.ChainPolicyAccept
for _, table := range n.getTables() {
// Create the filter table if it doesn't exist, this table name is the same
// as the name used by iptables-nft and ufw. We install rules into the
// same conventional table so that `accept` verdicts from our jump
// chains are conclusive.
filter, err := createTableIfNotExist(n.conn, table.Proto, "filter")
if err != nil {
return fmt.Errorf("create table: %w", err)
}
table.Filter = filter
// Adding the "conventional chains" that are used by iptables-nft and ufw.
if err = createChainIfNotExist(n.conn, chainInfo{filter, "FORWARD", nftables.ChainTypeFilter, nftables.ChainHookForward, nftables.ChainPriorityFilter, &polAccept}); err != nil {
return fmt.Errorf("create forward chain: %w", err)
}
if err = createChainIfNotExist(n.conn, chainInfo{filter, "INPUT", nftables.ChainTypeFilter, nftables.ChainHookInput, nftables.ChainPriorityFilter, &polAccept}); err != nil {
return fmt.Errorf("create input chain: %w", err)
}
// Adding the tailscale chains that contain our rules.
if err = createChainIfNotExist(n.conn, chainInfo{filter, chainNameForward, chainTypeRegular, nil, nil, nil}); err != nil {
return fmt.Errorf("create forward chain: %w", err)
}
if err = createChainIfNotExist(n.conn, chainInfo{filter, chainNameInput, chainTypeRegular, nil, nil, nil}); err != nil {
return fmt.Errorf("create input chain: %w", err)
}
// Create the nat table if it doesn't exist, this table name is the same
// as the name used by iptables-nft and ufw. We install rules into the
// same conventional table so that `accept` verdicts from our jump
// chains are conclusive.
nat, err := createTableIfNotExist(n.conn, table.Proto, "nat")
if err != nil {View on GitHub (pinned to 6e0912f979)
Solutions
- Retry AddChains; concurrent table mutations cause transient failures.
- Verify the filter table exists and inspect 'nft list ruleset'.
- Check capabilities and nftables backend availability.
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at util/linuxfw/nftables_runner.go:945 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18).
Data as JSON: /api/errors/fb809be039ef93a5.
Report an issue: GitHub.