jdx/mise · error
firewall rule '{}' is declared more than once
Error message
firewall rule '{}' is declared more than once What it means
Thrown while merging layered firewall config for `[bootstrap.linux.firewall]`: two rules in the same local mise.toml share one `name`. Rule names are the identity/merge key of the firewall ruleset (local rules override inherited ones by name), so duplicates inside one file are rejected during `merge_toml_config` before a request is ever built.
Source
Thrown at src/system/firewall.rs:320
// more local scalar or same-named rule overrides its inherited value.
for cf in config.config_files.values().rev() {
if let Some(bootstrap) = cf.bootstrap_config()
&& let Some(firewall) = bootstrap.linux.firewall
{
merged = Some(merge_toml_config(merged.unwrap_or_default(), firewall)?);
}
}
merged.map(FirewallRequest::from_toml).transpose()
}
fn merge_toml_config(
mut inherited: FirewallTomlConfig,
local: FirewallTomlConfig,
) -> Result<FirewallTomlConfig> {
let mut local_names = HashSet::new();
for rule in &local.rules {
if !local_names.insert(&rule.name) {
bail!("firewall rule '{}' is declared more than once", rule.name);
}
}
if local.backend.is_some() {
inherited.backend = local.backend;
}
if local.state.is_some() {
inherited.state = local.state;
}
if local.default_incoming.is_some() {
inherited.default_incoming = local.default_incoming;
}
if local.default_outgoing.is_some() {
inherited.default_outgoing = local.default_outgoing;
}
if local.exclusive.is_some() {
inherited.exclusive = local.exclusive;
}
if local.allow_lockout.is_some() {View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Rename one of the duplicates to a unique descriptive name (e.g. `web-http` and `web-https`).
- Delete the stale copy if it was left by an aborted edit.
- Remember names are merge keys across files: the same name in a local file intentionally overrides the inherited rule, but within one file names must be unique.
Example fix
# before (mise.toml) [[bootstrap.linux.firewall.rules]] name = "web" port = 80 protocol = "tcp" [[bootstrap.linux.firewall.rules]] name = "web" # duplicate port = 443 protocol = "tcp" # after [[bootstrap.linux.firewall.rules]] name = "web-http" port = 80 protocol = "tcp" [[bootstrap.linux.firewall.rules]] name = "web-https" port = 443 protocol = "tcp"
Defensive patterns
Strategy: validation
Validate before calling
# pre-flight: unique rule names per file
python3 - <<'PY'
import tomllib, collections
fw = tomllib.load(open('mise.toml','rb')).get('bootstrap',{}).get('linux',{}).get('firewall',{})
dupes = [n for n, c in collections.Counter(r['name'] for r in fw.get('rules',[])).items() if c > 1]
if dupes: raise SystemExit(f"duplicate firewall rule names: {dupes}")
PY Prevention
- Treat rule names as unique IDs; use descriptive suffixes (web-http, web-https).
- After copy-pasting a rule block, rename before saving.
- Lint config with `mise bootstrap firewall status` (parse-only).
When it happens
Trigger: Two `[[bootstrap.linux.firewall.rules]]` blocks in a single config file with the same `name = "web"` — typically after copy-pasting a rule block and forgetting to rename it.
Common situations: Copy-paste of rule blocks while iterating on config; merging hand-written snippets into one file; a rename that collides with an existing rule name.
Related errors
- firewall rule '{name}' is declared more than once
- firewall port '{range}' must be a number or inclusive range
- firewall port range {start}-{end} is invalid
- firewall rule '{name}' mixes IPv4 and IPv6 source/destinatio
- firewall rule '{name}' sets port without protocol
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/77304e46062d7b25.
Report an issue: GitHub.