jdx/mise · error
refusing firewall default incoming
Error message
refusing firewall default incoming {} over SSH: no incoming TCP allow rule covers peer {} on server port {} with an unrestricted interface; add a covering rule or set allow_lockout = true What it means
When changing the default incoming policy over SSH, mise requires positive proof that at least one incoming TCP allow rule covers your current peer (connection.peer) and server port with no interface restriction. After walking all rules, none qualifies (covered == false), so applying would almost certainly block your session and the change is refused.
Solutions
- Add an incoming allow rule matching your actual peer and SSH port, e.g. source = your client CIDR, port = sshd port, protocol = "tcp", action = "allow", no interface restriction.
- Fix the existing allow rule's port, source CIDR, or interface so it covers the current connection (check SSH_CONNECTION values).
- Set allow_lockout = true only if you have out-of-band console access.
Example fix
// before (SSH from 203.0.113.7 on port 22) [[firewall.rules]] name = "allow-ssh" source = "10.0.0.0/8" port = 22 protocol = "tcp" action = "allow" // after [[firewall.rules]] name = "allow-ssh" source = "203.0.113.7/32" port = 22 protocol = "tcp" action = "allow"
Defensive patterns
Strategy: validation
Validate before calling
let conn = std::env::var("SSH_CONNECTION").expect("SSH_CONNECTION");
let (peer, _sport, server_port) = parse_ssh_fields(&conn);
let covered = rules.iter().any(|r| r.is_incoming_allow_tcp(peer, server_port) && r.interface.is_none());
if !covered { eprintln!("no allow rule covers {peer} on {server_port}; add one before applying"); } Type guard
fn ssh_is_covered(rules: &[FirewallRule], peer: IpAddr, server_port: u16) -> bool {
rules.iter().any(|r| r.direction == Direction::Incoming
&& r.action.preserves_access()
&& r.protocol == Some(Protocol::Tcp)
&& r.port.map(|p| p.contains(server_port)).unwrap_or(false)
&& r.source.as_ref().map(|s| s.contains(&peer)).unwrap_or(true)
&& r.interface.is_none())
} Try / catch
match result {
Err(e) if e.to_string().contains("no incoming TCP allow rule covers") => {
eprintln!("add an allow rule for the peer/port from SSH_CONNECTION");
}
other => other?,
} Prevention
- Compare your allow rule's port/source with `echo $SSH_CONNECTION` before applying.
- If sshd runs on a custom port, mirror it in the firewall rule.
- Avoid binding the SSH allow rule to a specific interface unless certain of the ingress device.
- Add rules for both IPv4 and IPv6 if the host is dual-stack.
When it happens
Trigger: `mise bootstrap firewall apply` over SSH where every rule either: is not incoming, is not allow/preserving, does not restrict to tcp/22 (server_port), does not contain connection.peer in its source network, or binds to a specific interface that is not the SSH ingress.
Common situations: SSH allow rule written for the wrong port (e.g. 22 vs a custom Port in sshd_config); allow rule limited to a LAN source while you SSH from a WAN/VPN address; rule bound to eth0 while SSH arrives over tails0/wg0; IPv6 SSH session but only IPv4 allow rules defined.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- refusing firewall default incoming
- refusing firewall default incoming
- refusing firewall default incoming
- refusing firewall default incoming
- SSH_CONNECTION must contain client address/port and server…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/2f51095e9f8d8aa4.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/firewall.rs:545
_ => {}
}
continue;
}
// SSH_CONNECTION does not identify the ingress interface. An
// interface-constrained allow cannot prove that it preserves this
// session, so keep looking for an unrestricted covering allow.
if rule.interface.is_none() {
covered = true;
if matches!(
backend,
Some(FirewallBackend::Nftables | FirewallBackend::Ufw)
) {
break;
}
}
}
if !covered {
bail!(
"refusing firewall default incoming {} over SSH: no incoming TCP allow rule covers peer {} on server port {} with an unrestricted interface; add a covering rule or set allow_lockout = true",
self.default_incoming.ufw(),
connection.peer,
connection.server_port
);
}
Ok(())
}
pub(crate) fn plans(&self) -> Vec<ResourcePlan> {
let inspection = self.inspection.as_ref();
let backend = inspection
.and_then(|inspection| inspection.backend)
.unwrap_or(self.backend);
let desired = format!(
"{} via {}; incoming {}; outgoing {}; {}",
match self.state {
FirewallState::Enabled => "enabled",View on GitHub (pinned to 533346cc37)