{"record":{"id":"fb809be039ef93a5","repo":"tailscale/tailscale","slug":"create-forward-chain-w","errorCode":null,"errorMessage":"create forward chain: %w","messagePattern":"create forward chain: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/linuxfw/nftables_runner.go","lineNumber":945,"sourceCode":"}\n\n// AddChains creates custom Tailscale chains in netfilter via nftables\n// if the ts-chain doesn't already exist.\nfunc (n *nftablesRunner) AddChains() error {\n\tpolAccept := nftables.ChainPolicyAccept\n\tfor _, table := range n.getTables() {\n\t\t// Create the filter table if it doesn't exist, this table name is the same\n\t\t// as the name used by iptables-nft and ufw. We install rules into the\n\t\t// same conventional table so that `accept` verdicts from our jump\n\t\t// chains are conclusive.\n\t\tfilter, err := createTableIfNotExist(n.conn, table.Proto, \"filter\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"create table: %w\", err)\n\t\t}\n\t\ttable.Filter = filter\n\t\t// Adding the \"conventional chains\" that are used by iptables-nft and ufw.\n\t\tif err = createChainIfNotExist(n.conn, chainInfo{filter, \"FORWARD\", nftables.ChainTypeFilter, nftables.ChainHookForward, nftables.ChainPriorityFilter, &polAccept}); err != nil {\n\t\t\treturn fmt.Errorf(\"create forward chain: %w\", err)\n\t\t}\n\t\tif err = createChainIfNotExist(n.conn, chainInfo{filter, \"INPUT\", nftables.ChainTypeFilter, nftables.ChainHookInput, nftables.ChainPriorityFilter, &polAccept}); err != nil {\n\t\t\treturn fmt.Errorf(\"create input chain: %w\", err)\n\t\t}\n\t\t// Adding the tailscale chains that contain our rules.\n\t\tif err = createChainIfNotExist(n.conn, chainInfo{filter, chainNameForward, chainTypeRegular, nil, nil, nil}); err != nil {\n\t\t\treturn fmt.Errorf(\"create forward chain: %w\", err)\n\t\t}\n\t\tif err = createChainIfNotExist(n.conn, chainInfo{filter, chainNameInput, chainTypeRegular, nil, nil, nil}); err != nil {\n\t\t\treturn fmt.Errorf(\"create input chain: %w\", err)\n\t\t}\n\n\t\t// Create the nat table if it doesn't exist, this table name is the same\n\t\t// as the name used by iptables-nft and ufw. We install rules into the\n\t\t// same conventional table so that `accept` verdicts from our jump\n\t\t// chains are conclusive.\n\t\tnat, err := createTableIfNotExist(n.conn, table.Proto, \"nat\")\n\t\tif err != nil {","sourceCodeStart":927,"sourceCodeEnd":963,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/util/linuxfw/nftables_runner.go#L927-L963","documentation":"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.","triggerScenarios":"Thrown at util/linuxfw/nftables_runner.go:945 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"6e0912f97994f927632b34ae9e63b53d6516a6ac","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}