{"record":{"id":"67c15c9bbc0cb267","repo":"jdx/mise","slug":"firewall-port-range-start-end-is-invalid","errorCode":null,"errorMessage":"firewall port range {start}-{end} is invalid","messagePattern":"firewall port range (.+?)-(.+?) is invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/firewall.rs","lineNumber":196,"sourceCode":"#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]\npub struct FirewallPort {\n    start: u16,\n    end: u16,\n}\n\nimpl FirewallPort {\n    fn from_toml(value: FirewallPortToml) -> Result<Self> {\n        let (start, end) = match value {\n            FirewallPortToml::Single(port) => (port, port),\n            FirewallPortToml::Range(range) => {\n                let Some((start, end)) = range.split_once(['-', ':']) else {\n                    bail!(\"firewall port '{range}' must be a number or inclusive range\")\n                };\n                (start.parse()?, end.parse()?)\n            }\n        };\n        if start == 0 || end == 0 || start > end {\n            bail!(\"firewall port range {start}-{end} is invalid\");\n        }\n        Ok(Self { start, end })\n    }\n\n    fn contains(self, port: u16) -> bool {\n        self.start <= port && port <= self.end\n    }\n\n    fn render(self, separator: char) -> String {\n        if self.start == self.end {\n            self.start.to_string()\n        } else {\n            format!(\"{}{separator}{}\", self.start, self.end)\n        }\n    }\n}\n\n#[derive(Clone, Debug, Deserialize)]","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/firewall.rs#L178-L214","documentation":"Validates the parsed port range of a firewall rule: after splitting the string, both endpoints must be non-zero u16 values and start must not exceed end (`start == 0 || end == 0 || start > end` aborts). Firewall ports are 1-65535 and the range is inclusive. Ports above 65535 fail earlier as a u16 parse error, so this message specifically covers zero or reversed bounds.","triggerScenarios":"`port = \"0-65535\"` or `port = 0` (zero is not a valid port), or a reversed range such as `port = \"9000-8000\"` where start > end after parsing.","commonSituations":"Writing ranges backwards assuming they are normalized; using 0 as a wildcard meaning \"any port\" (not supported — omit `port` instead); inverted ranges copied from another tool's output.","solutions":["Order the range ascending: `port = \"8000-9000\"`.","Never use port 0 — to match all ports, omit the `port` key entirely (then `protocol` is also optional).","Re-check typos where bounds and separator got mangled (\"80-.443\", \"80:-443\").","Run `mise bootstrap firewall status` after editing to surface config errors without touching the firewall."],"exampleFix":"# before\n[[bootstrap.linux.firewall.rules]]\nname = \"high-ports\"\nport = \"9000-8000\"\nprotocol = \"udp\"\n\n# after\n[[bootstrap.linux.firewall.rules]]\nname = \"high-ports\"\nport = \"8000-9000\"\nprotocol = \"udp\"","handlingStrategy":"validation","validationCode":"# pre-flight: ranges ascending, no zero endpoints\npython3 - <<'PY'\nimport tomllib\nfw = tomllib.load(open('mise.toml','rb')).get('bootstrap',{}).get('linux',{}).get('firewall',{})\nfor r in fw.get('rules',[]):\n    p = r.get('port')\n    if isinstance(p, str) and '-' in p or isinstance(p, str) and ':' in p:\n        a, b = p.replace(':', '-').split('-', 1)\n        if not (1 <= int(a) <= int(b) <= 65535):\n            raise SystemExit(f\"rule {r['name']}: invalid port range {p}\")\nPY","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Write ranges ascending; mise does not normalize them.","Port 0 is never valid — omit `port` to match all ports.","Validate config with `mise bootstrap firewall status` before apply."],"tags":["mise","firewall","port-range","bootstrap","validation","config"],"backgroundTag":"invalid-port-range","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}