jdx/mise · error
firewall rule '{name}' sets port without protocol
Error message
firewall rule '{name}' sets port without protocol What it means
In `[bootstrap.linux.firewall]`, a rule that sets `port` must also set `protocol` (tcp, udp, sctp, or dccp) because every firewall backend needs a protocol to render a port match. This error fires while building the FirewallRequest when `port` is present and `protocol` is absent. There is no default protocol — the config must be explicit.
Source
Thrown at src/system/firewall.rs:417
.source
.map(|source| source.parse::<IpNet>())
.transpose()
.wrap_err_with(|| format!("firewall rule '{name}' has an invalid source"))?;
let destination = rule
.destination
.map(|destination| destination.parse::<IpNet>())
.transpose()
.wrap_err_with(|| format!("firewall rule '{name}' has an invalid destination"))?;
if source.is_some_and(|source| {
destination.is_some_and(|destination| {
source.addr().is_ipv4() != destination.addr().is_ipv4()
})
}) {
bail!("firewall rule '{name}' mixes IPv4 and IPv6 source/destination networks");
}
let port = rule.port.map(FirewallPort::from_toml).transpose()?;
if port.is_some() && rule.protocol.is_none() {
bail!("firewall rule '{name}' sets port without protocol");
}
rules.push(FirewallRule {
name,
state: rule.state,
direction: rule.direction,
action: rule.action,
port,
protocol: rule.protocol,
source,
destination,
interface,
});
}
let ssh_connection = std::env::var("SSH_CONNECTION")
.ok()
.map(|value| parse_ssh_connection(&value))
.transpose()?;
let request = Self {View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Add `protocol = "tcp"` (or "udp") to the rule.
- If both protocols are needed, create two rules with the same constraints but different protocols.
- Note sctp/dccp are only usable with the nftables/firewalld backends — ufw rejects them (see the separate validation error).
Example fix
# before [[bootstrap.linux.firewall.rules]] name = "ssh" port = 22 # after [[bootstrap.linux.firewall.rules]] name = "ssh" port = 22 protocol = "tcp"
Defensive patterns
Strategy: validation
Validate before calling
# pre-flight: port requires protocol
python3 - <<'PY'
import tomllib
fw = tomllib.load(open('mise.toml','rb')).get('bootstrap',{}).get('linux',{}).get('firewall',{})
for r in fw.get('rules',[]):
if 'port' in r and 'protocol' not in r:
raise SystemExit(f"rule {r['name']}: sets port without protocol")
PY Prevention
- There is no default protocol — always pair port with protocol.
- Porting ufw commands? Translate `ufw allow 22` into two rules (tcp and udp) or pick one.
- Run `mise bootstrap firewall status` to parse-check config before apply.
When it happens
Trigger: A rule containing `port = 22` (or `port = "22-30"`) with no `protocol` key; the check is `port.is_some() && rule.protocol.is_none()` after the port is successfully parsed.
Common situations: Porting rules from ufw syntax (`ufw allow 22` implicitly means tcp+udp) where protocol looks redundant; trimming config to minimal keys; assuming a tcp default like SSH-oriented examples often show.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- firewall port '{range}' must be a number or inclusive range
- firewall port range {start}-{end} is invalid
- firewall rule '{}' is declared more than once
- firewall rule '{name}' is declared more than once
- firewall rule '{name}' mixes IPv4 and IPv6 source/destinatio
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/6b6e6c28a9691f5d.
Report an issue: GitHub.