jdx/mise · error
refusing unsafe firewall change; inspect `mise bootstrap fir
Error message
refusing unsafe firewall change; inspect `mise bootstrap firewall status`
What it means
A fail-closed safety stop in firewall apply: the computed plan contains at least one resource whose action is `Unknown` — mise could not determine its current state — and the run is not `--dry-run`. mise will not modify a firewall it cannot fully see, so it refuses and points at `mise bootstrap firewall status` for diagnosis. In dry-run mode the same condition only prints 'would not change ... (manual action required)' warnings.
Source
Thrown at src/system/firewall.rs:717
.count();
if changes == 0 {
info!("firewall: already converged");
return Ok(());
}
if firewall_change_is_unsafe(&plan) {
if dry_run {
for resource in plan
.iter()
.filter(|resource| resource.action == ResourceAction::Unknown)
{
warn!(
"would not change {}: current {}, desired {} (manual action required)",
resource.id, resource.current, resource.desired
);
}
return Ok(());
}
bail!("refusing unsafe firewall change; inspect `mise bootstrap firewall status`");
}
if dry_run {
let inspection = request.inspection.as_ref().expect("firewall was inspected");
let backend = inspection.backend.expect("available firewall backend");
for command in preview_commands(request, backend)? {
miseprintln!("would run {}", shell_words::join(command));
}
return Ok(());
}
let destructive = request.exclusive
|| matches!(
request.state,
FirewallState::Disabled | FirewallState::Absent
)
|| plan
.iter()
.any(|resource| resource.action == ResourceAction::Remove);
if !yesView on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Run `mise bootstrap firewall status` to see current vs desired per resource and identify the indeterminate one.
- Run `mise bootstrap firewall apply --dry-run` — every 'would not change X ... (manual action required)' line is an item you must reconcile by hand.
- Remove or normalize the out-of-band object with the backend's own CLI (`nft delete rule ...`, `firewall-cmd`, `ufw delete`), then re-run apply so inspection sees a known state.
- Check backend health and version (`nft --version`, `firewall-cmd --state`, `ufw status`) — a broken backend produces unparseable output.
Example fix
# before mise bootstrap firewall apply # error: refusing unsafe firewall change; inspect `mise bootstrap firewall status` # after — diagnose, reconcile manually, re-run mise bootstrap firewall status mise bootstrap firewall apply --dry-run # lists 'manual action required' items sudo nft delete rule inet filter unknown-rule-handle-42 # example manual fix mise bootstrap firewall apply
Defensive patterns
Strategy: try-catch
Validate before calling
# pre-flight: make the unknowns visible without changing anything mise bootstrap firewall apply --dry-run # 'manual action required' lines = items to reconcile
Try / catch
if ! mise bootstrap firewall apply 2>fw.err; then
if grep -q "refusing unsafe firewall change" fw.err; then
mise bootstrap firewall status # inspect current vs desired
exit 1 # reconcile manually, then re-run
fi
cat fw.err; exit 1
fi Prevention
- Never manage the same rules with two tools — converge everything through one config.
- Treat dry-run 'manual action required' lines as a pre-apply checklist.
- Keep nft/firewalld/ufw updated so inspection output stays parseable.
When it happens
Trigger: `mise bootstrap firewall apply` where inspection marked some resource's action Unknown: backend command present but its output could not be parsed/mapped, exotic rules created out-of-band by other tools, or firewall state changed between inspect and plan. The bail sits on the non-dry-run path right after the Unknown-warning loop.
Common situations: Firewalls partially managed by other tools (shorewall, cloud host agents, hand-run nft commands) leaving structures the inspection cannot map; version skew between the installed nft/firewalld/ufw output format and mise's parsers; a previously interrupted apply leaving half-created objects.
Related errors
- no supported firewall backend found (tried nft, firewall-cmd
- firewall rule name '{name}' must contain only ASCII letters,
- bootstrap firewall management is only supported on Linux
- bootstrap users and groups are only supported on Linux
- refusing unsafe change to bootstrap group '{}'; inspect `mis
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/3edebdd1a540b3be.
Report an issue: GitHub.