jdx/mise · error
firewall rule '{}' uses interface matching, which firewalld
Error message
firewall rule '{}' uses interface matching, which firewalld policies cannot express safely; select backend = \"nftables\" or \"ufw\" What it means
Interface matching (`interface = "eth0"` on a rule) cannot be expressed safely in firewalld policies — firewalld zone/policy semantics cannot guarantee the intended match — so `validate_backend_request` rejects any interface-using rule when the effective backend is firewalld. nftables and ufw both support interface matches, so the fix is to pin one of those backends or drop the `interface` key.
Source
Thrown at src/system/firewall.rs:1033
&& [FIREWALLD_INCOMING, FIREWALLD_OUTGOING]
.iter()
.all(|policy| {
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 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::Ufw
&& matches!(
rule.protocol,
Some(FirewallProtocol::Sctp | FirewallProtocol::Dccp)
)
{
bail!(
"firewall rule '{}' uses protocol {}, which UFW does not support; select backend = \"nftables\" or \"firewalld\"",
rule.name,
rule.protocol.expect("matched protocol").as_str()
);
}
}
Ok(())View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Pin `backend = "nftables"` or `backend = "ufw"` in `[bootstrap.linux.firewall]` (installing that backend if needed).
- Remove the `interface` key from the flagged rule and constrain by `source`/`destination` CIDR instead.
- If firewalld is mandatory, handle the interface constraint outside mise (firewalld zone/interface assignment) and keep the rule interface-free.
Example fix
# before (mise.toml) [bootstrap.linux.firewall] backend = "firewalld" [[bootstrap.linux.firewall.rules]] name = "lan" interface = "eth0" port = 5353 protocol = "udp" action = "allow" # after [bootstrap.linux.firewall] backend = "nftables" [[bootstrap.linux.firewall.rules]] name = "lan" interface = "eth0" port = 5353 protocol = "udp" action = "allow"
Defensive patterns
Strategy: validation
Validate before calling
# pre-flight: interface rules require nftables/ufw
python3 - <<'PY'
import tomllib
fw = tomllib.load(open('mise.toml','rb')).get('bootstrap',{}).get('linux',{}).get('firewall',{})
if fw.get('backend') == 'firewalld' and any('interface' in r for r in fw.get('rules',[])):
raise SystemExit('firewalld cannot express interface matching; use backend = "nftables"/"ufw"')
PY Prevention
- Pin the backend explicitly in configs ported across distros.
- Prefer source-CIDR matching over interface matching for portability.
- Check rule features against the backend matrix before authoring.
When it happens
Trigger: `backend = "firewalld"` (or auto-detection resolving to firewalld) combined with any `[[bootstrap.linux.firewall.rules]]` entry that has an `interface` key — validated up front, before planning or dry-run output.
Common situations: RHEL-family hosts defaulting to firewalld while the config was authored on an Ubuntu/ufw or nftables machine; porting interface-scoped rules across distros; sharing dotfiles/bootstrap configs in mixed fleets.
Related errors
- firewall backend '{}' requires command '{}'
- firewall rule '{}' uses protocol {}, which UFW does not supp
- firewall port '{range}' must be a number or inclusive range
- firewall port range {start}-{end} is invalid
- firewall rule '{}' is declared more than once
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/36a0fec3fb7c69f9.
Report an issue: GitHub.