{"record":{"id":"79ec4f1a9f7ad2d9","repo":"netbirdio/netbird","slug":"list-rules-for-chain-s-w","errorCode":null,"errorMessage":"list rules for chain %s: %w","messagePattern":"list rules for chain (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/nftables/router_linux.go","lineNumber":1536,"sourceCode":"\n\tdelete(r.rules, ruleKey)\n\n\tif err := r.decrementSetCounter(rule); err != nil {\n\t\treturn fmt.Errorf(\"decrement set counter: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// refreshRulesMap rebuilds the rule map from the kernel. This removes stale entries\n// (e.g. from failed flushes) and updates handles for all existing rules.\nfunc (r *router) refreshRulesMap() error {\n\tvar merr *multierror.Error\n\tnewRules := make(map[string]*nftables.Rule)\n\tfor _, chain := range r.chains {\n\t\trules, err := r.conn.GetRules(chain.Table, chain)\n\t\tif err != nil {\n\t\t\tmerr = multierror.Append(merr, fmt.Errorf(\"list rules for chain %s: %w\", chain.Name, err))\n\t\t\t// preserve existing entries for this chain since we can't verify their state\n\t\t\tfor k, v := range r.rules {\n\t\t\t\tif v.Chain != nil && v.Chain.Name == chain.Name {\n\t\t\t\t\tnewRules[k] = v\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tfor _, rule := range rules {\n\t\t\tif len(rule.UserData) > 0 {\n\t\t\t\tnewRules[string(rule.UserData)] = rule\n\t\t\t}\n\t\t}\n\t}\n\tr.rules = newRules\n\treturn nberrors.FormatErrorOrNil(merr)\n}\n","sourceCodeStart":1518,"sourceCodeEnd":1554,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/nftables/router_linux.go#L1518-L1554","documentation":"refreshRulesMap rebuilds r.rules by dumping every netbird chain with nftables.Conn.GetRules; this error wraps a per-chain NFT_MSG_GETRULE dump failure. The function deliberately keeps the previously cached entries for the failing chain, continues with the other chains, and returns all failures as a multierror. It gates AddNatRule, RemoveNatRule, DeleteDNATRule and RemoveInboundDNAT, so those surface it as 'refresh rules map: list rules for chain ...'.","triggerScenarios":"GetRules returns a netlink error: the table or chain no longer exists (ENOENT after an external flush), the process lacks CAP_NET_ADMIN, or a very large ruleset truncates the netlink dump.","commonSituations":"Configuration management or host hardening wipes nftables state under the agent; agent in a container without NET_ADMIN; firewalld switching backends and recreating tables; huge ACL rulesets.","solutions":["Inspect kernel state with 'sudo nft list tables' and 'sudo nft list table <netbird table>' to see whether the chain still exists.","Run the agent as root or grant CAP_NET_ADMIN for netlink dumps.","If the table was flushed externally, restart the agent so init recreates tables, chains and rules.","Match the chain name in the nested error against 'nft list chains' to spot renames or backend switches."],"exampleFix":"// before\nif err := r.refreshRulesMap(); err != nil {\n    return fmt.Errorf(refreshRulesMapError, err)\n}\n\n// after: per-chain failures already preserve cached entries; report and let callers retry\nif err := r.refreshRulesMap(); err != nil {\n    log.Warnf(\"rules map refresh incomplete, cached handles kept: %v\", err)\n}","handlingStrategy":"retry","validationCode":"// Preflight: verify the netbird chains still exist before a refresh-dependent operation\nfunc chainsPresent(conn *nftables.Conn, table *nftables.Table, names []string) error {\n    for _, name := range names {\n        if _, err := conn.GetChain(table, name); err != nil {\n            return fmt.Errorf(\"chain %s missing: %w\", name, err)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := r.refreshRulesMap(); err != nil {\n    if errors.Is(err, unix.ENOENT) || errors.Is(err, unix.EAGAIN) {\n        // dump raced a ruleset change: retry once before failing\n        if err2 := r.refreshRulesMap(); err2 == nil {\n            return nil\n        }\n    }\n    return fmt.Errorf(refreshRulesMapError, err)\n}","preventionTips":["Never flush the netbird tables externally while routes are configured; resync tooling with the agent lifecycle instead.","Run the agent with CAP_NET_ADMIN so dumps cannot fail on permissions.","Keep rulesets modest in size or raise netlink buffer limits on hosts with many rules."],"tags":["nftables","netlink","ruleset","linux"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}