{"record":{"id":"89404846466457e0","repo":"jdx/mise","slug":"firewall-rule-uses-action-limit-which-re","errorCode":null,"errorMessage":"firewall rule '{}' uses action = \"limit\", which requires direction = \"incoming\" and protocol = \"tcp\"","messagePattern":"firewall rule '(.+?)' uses action = \"limit\", which requires direction = \"incoming\" and protocol = \"tcp\"","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/firewall.rs","lineNumber":1046,"sourceCode":"                        command_output(\n                            \"firewall-cmd\",\n                            &[\"--permanent\", &format!(\"--info-policy={policy}\")],\n                        )\n                        .is_ok_and(|output| output.status.success())\n                    })\n        }\n        FirewallBackend::Ufw => backend_active(backend),\n        FirewallBackend::Auto => false,\n    }\n}\n\nfn validate_backend_request(request: &FirewallRequest, backend: FirewallBackend) -> Result<()> {\n    for rule in &request.rules {\n        if rule.action == FirewallAction::Limit {\n            if rule.direction != FirewallDirection::Incoming\n                || rule.protocol != Some(FirewallProtocol::Tcp)\n            {\n                bail!(\n                    \"firewall rule '{}' uses action = \\\"limit\\\", which requires direction = \\\"incoming\\\" and protocol = \\\"tcp\\\"\",\n                    rule.name\n                );\n            }\n            if backend == FirewallBackend::Firewalld {\n                bail!(\n                    \"firewall rule '{}' uses per-source connection limiting, which firewalld policies cannot express safely; select backend = \\\"nftables\\\" or \\\"ufw\\\"\",\n                    rule.name\n                );\n            }\n        }\n        if backend == FirewallBackend::Firewalld && rule.interface.is_some() {\n            bail!(\n                \"firewall rule '{}' uses interface matching, which firewalld policies cannot express safely; select backend = \\\"nftables\\\" or \\\"ufw\\\"\",\n                rule.name\n            );\n        }\n        if backend == FirewallBackend::Ufw","sourceCodeStart":1028,"sourceCodeEnd":1064,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/firewall.rs#L1028-L1064","documentation":"Rule-level semantic validation: the `limit` action (per-source connection rate limiting) is only expressible for incoming TCP rules. A rule with `action = \"limit\"` but direction not `incoming` or protocol not `tcp` is rejected before any backend command runs, because no supported backend can translate it correctly.","triggerScenarios":"Defining a firewall rule with `action = \"limit\"` and either `direction = \"outgoing\"` or a protocol other than `tcp` (e.g. udp, sctp) in the bootstrap firewall config, then running inspect/apply.","commonSituations":"Copy-pasting a rate-limited SSH rule template and changing direction/protocol; intending to rate-limit UDP traffic; misremembering that limit applies only to inbound TCP connection throttling.","solutions":["Set `direction = \"incoming\"` and `protocol = \"tcp\"` on the rule using `action = \"limit\"`","Or change the action to `allow`/`deny` if you do not actually need rate limiting","Split the intent: keep the limit rule for incoming TCP, define separate allow/deny rules for other protocols/directions"],"exampleFix":"// before\n[[rule]]\nname = \"rate-limit-dns\"\naction = \"limit\"\ndirection = \"outgoing\"\nprotocol = \"udp\"\n// after\n[[rule]]\nname = \"rate-limit-ssh\"\naction = \"limit\"\ndirection = \"incoming\"\nprotocol = \"tcp\"","handlingStrategy":"validation","validationCode":"// pre-check in config lint\nfunction validLimitRule(r) {\n  return r.action !== \"limit\" || (r.direction === \"incoming\" && r.protocol === \"tcp\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember `limit` means incoming-TCP connection rate limiting only","Add a config-lint check that every action=\"limit\" rule has direction=incoming and protocol=tcp","Use allow/deny for anything not rate-limiting inbound TCP","Keep a documented template for limit rules and copy from it"],"tags":["firewall","validation","rule-config","rate-limit"],"backgroundTag":"invalid-config-value","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}