jdx/mise · error

firewall backend '{}' requires command '{}'

Error message

firewall backend '{}' requires command '{}'

What it means

The config pins a specific firewall backend via `backend = "nftables" | "firewalld" | "ufw"`, but `ensure_backend_available` found that backend's CLI program is not on PATH, so mise refuses rather than silently switching backends. The message names both the selected backend label and the exact missing command. Install it, or drop/changed the `backend` key to let auto-detection pick what exists.

Source

Thrown at src/system/firewall.rs:983

        }
    }
    for backend in [
        FirewallBackend::Nftables,
        FirewallBackend::Firewalld,
        FirewallBackend::Ufw,
    ] {
        if backend_available(backend) {
            return Ok(backend);
        }
    }
    bail!("no supported firewall backend found (tried nft, firewall-cmd, and ufw)")
}

fn ensure_backend_available(backend: FirewallBackend) -> Result<()> {
    if backend_available(backend) {
        Ok(())
    } else {
        bail!(
            "firewall backend '{}' requires command '{}'",
            backend.label(),
            backend.program().unwrap_or_default()
        )
    }
}

fn backend_available(backend: FirewallBackend) -> bool {
    backend.program().and_then(crate::file::which).is_some()
}

fn backend_active(backend: FirewallBackend) -> bool {
    match backend {
        FirewallBackend::Nftables => command_output("nft", &["list", "table", "inet", NFT_TABLE])
            .is_ok_and(|output| output.status.success()),
        FirewallBackend::Firewalld => {
            command_output("firewall-cmd", &["--state"]).is_ok_and(|output| output.status.success())
        }

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Install the named command: `apt install ufw`, `dnf install nftables`, `apt install nftables`, etc.
  2. Or drop `backend` from `[bootstrap.linux.firewall]` so auto-detection (nft, then firewall-cmd, then ufw) picks an installed one.
  3. Or change `backend` to the tool this host actually ships.
  4. Ensure the program is on PATH for the invoking context: `sudo env PATH="$PATH:/usr/sbin:/sbin" mise ...`.

Example fix

# before (mise.toml)
[bootstrap.linux.firewall]
backend = "ufw"        # ufw not installed on this host

# after — let mise pick what exists
[bootstrap.linux.firewall]
# backend omitted; auto-detects nft -> firewall-cmd -> ufw
# or pin what is installed: backend = "nftables"
Defensive patterns

Strategy: fallback

Validate before calling

# pre-flight: the pinned backend's program must be on PATH
case "$BACKEND" in
  nftables) command -v nft >/dev/null || echo 'install nftables' ;;
  firewalld) command -v firewall-cmd >/dev/null || echo 'install firewalld' ;;
  ufw) command -v ufw >/dev/null || echo 'install ufw' ;;
esac

Prevention

When it happens

Trigger: `backend = "ufw"` on a firewalld-only RHEL box; `backend = "nftables"` where nft is not installed; or the command exists but is unreachable through the invoking PATH (sudo secure_path excluding /usr/sbin). Checked before any inspection or apply work.

Common situations: Sharing one mise.toml across heterogeneous hosts where only some have the pinned backend; minimal images; scripts that run mise under a reduced PATH; migrating configs from ufw machines to nftables-only servers.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/a4a26e96a32d8581. Report an issue: GitHub.