{"record":{"id":"4de44c90bc3b55db","repo":"jdx/mise","slug":"firewall-rule-name-name-must-contain-only-asci","errorCode":null,"errorMessage":"firewall rule name '{name}' must contain only ASCII letters, numbers, '-' or '_'","messagePattern":"firewall rule name '(.+?)' must contain only ASCII letters, numbers, '-' or '_'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/firewall.rs","lineNumber":2033,"sourceCode":"fn command_error(program: &str, args: &[&str], output: &Output) -> eyre::Report {\n    eyre!(\n        \"{} failed with {}: {}\",\n        shell_words::join(\n            std::iter::once(program.to_string()).chain(args.iter().map(|arg| (*arg).to_string()))\n        ),\n        output.status,\n        String::from_utf8_lossy(&output.stderr).trim()\n    )\n}\n\nfn validate_name(name: &str) -> Result<()> {\n    if name.is_empty()\n        || name.len() > 64\n        || !name\n            .bytes()\n            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_'))\n    {\n        bail!(\"firewall rule name '{name}' must contain only ASCII letters, numbers, '-' or '_'\");\n    }\n    Ok(())\n}\n\nfn validate_interface(interface: &str) -> Result<String> {\n    if interface.is_empty()\n        || interface.len() > 15\n        || !interface\n            .bytes()\n            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_' | b'.' | b':'))\n    {\n        bail!(\"firewall interface '{interface}' is invalid\");\n    }\n    Ok(interface.to_string())\n}\n\nfn parse_ssh_connection(value: &str) -> Result<SshConnection> {\n    let fields = value.split_ascii_whitespace().collect::<Vec<_>>();","sourceCodeStart":2015,"sourceCodeEnd":2051,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/firewall.rs#L2015-L2051","documentation":"Rule names are used as identifiers in backend commands and must be 1-64 bytes of ASCII letters, digits, '-' or '_'. Validation bails with the offending name when it is empty, longer than 64 bytes, or contains any other character (spaces, slashes, unicode, etc.). This keeps generated backend commands safe and predictable.","triggerScenarios":"Calling rule-name validation with a name containing spaces or special characters (\"web server!\", \"db/allow\"), an empty string, unicode characters, or a name longer than 64 characters.","commonSituations":"Human-friendly names with spaces typed directly into config; names interpolated from service labels or hostnames that include dots or colons; overlong descriptive names past the 64-byte cap; non-ASCII input from localized config files.","solutions":["Rename the rule to use only A-Z, a-z, 0-9, '-' and '_', keeping it 64 bytes or fewer.","Trim/replace whitespace and strip disallowed punctuation in your config layer before constructing the rule.","Enforce the charset with a regex like ^[A-Za-z0-9_-]{1,64}$ when loading user-supplied names.","Use slugs (kebab-case) as the naming convention for all rules."],"exampleFix":"// before\nlet name = \"allow web traffic\"; // invalid: spaces\n// after\nlet name = \"allow-web-traffic\";","handlingStrategy":"validation","validationCode":"fn is_valid_rule_name(name: &str) -> bool {\n    !name.is_empty()\n        && name.len() <= 64\n        && name.bytes().all(|b| b.is_ascii_alphanumeric() || matches!(b, b'-' | b'_'))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use kebab-case slugs for rule names","Slugify any user/host-derived names before use","Enforce ^[A-Za-z0-9_-]{1,64}$ in config parsing","Keep descriptive text in comments/description fields, not the name"],"tags":["firewall","validation","naming"],"backgroundTag":"invalid-identifier-format","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}