jdx/mise · error
firewall rule '{}' uses action = "limit", which requires dir
Error message
firewall rule '{}' uses action = "limit", which requires direction = "incoming" and protocol = "tcp" What it means
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.
Source
Thrown at src/system/firewall.rs:1046
command_output(
"firewall-cmd",
&["--permanent", &format!("--info-policy={policy}")],
)
.is_ok_and(|output| output.status.success())
})
}
FirewallBackend::Ufw => backend_active(backend),
FirewallBackend::Auto => false,
}
}
fn validate_backend_request(request: &FirewallRequest, backend: FirewallBackend) -> Result<()> {
for rule in &request.rules {
if rule.action == FirewallAction::Limit {
if rule.direction != FirewallDirection::Incoming
|| rule.protocol != Some(FirewallProtocol::Tcp)
{
bail!(
"firewall rule '{}' uses action = \"limit\", which requires direction = \"incoming\" and protocol = \"tcp\"",
rule.name
);
}
if backend == FirewallBackend::Firewalld {
bail!(
"firewall rule '{}' uses per-source connection limiting, which firewalld policies cannot express safely; select backend = \"nftables\" or \"ufw\"",
rule.name
);
}
}
if backend == FirewallBackend::Firewalld && rule.interface.is_some() {
bail!(
"firewall rule '{}' uses interface matching, which firewalld policies cannot express safely; select backend = \"nftables\" or \"ufw\"",
rule.name
);
}
if backend == FirewallBackend::UfwView on GitHub (pinned to afd2eddd3a)
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
Example fix
// before [[rule]] name = "rate-limit-dns" action = "limit" direction = "outgoing" protocol = "udp" // after [[rule]] name = "rate-limit-ssh" action = "limit" direction = "incoming" protocol = "tcp"
Defensive patterns
Strategy: validation
Validate before calling
// pre-check in config lint
function validLimitRule(r) {
return r.action !== "limit" || (r.direction === "incoming" && r.protocol === "tcp");
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- firewall rule '{}' uses per-source connection limiting, whic
- firewall rule name '{name}' must contain only ASCII letters,
- firewall interface '{interface}' is invalid
- remote rustc action metadata is invalid
- remote action output directory is invalid
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/89404846466457e0.
Report an issue: GitHub.