jdx/mise · error

firewall rule name ' ' must contain only ASCII letters…

Error message

firewall rule name '{name}' must contain only ASCII letters, numbers, '-' or '_'

What it means

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.

Solutions

  1. Rename the rule to use only A-Z, a-z, 0-9, '-' and '_', keeping it 64 bytes or fewer.
  2. Trim/replace whitespace and strip disallowed punctuation in your config layer before constructing the rule.
  3. Enforce the charset with a regex like ^[A-Za-z0-9_-]{1,64}$ when loading user-supplied names.
  4. Use slugs (kebab-case) as the naming convention for all rules.

Example fix

// before
let name = "allow web traffic"; // invalid: spaces
// after
let name = "allow-web-traffic";
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_rule_name(name: &str) -> bool {
    !name.is_empty()
        && name.len() <= 64
        && name.bytes().all(|b| b.is_ascii_alphanumeric() || matches!(b, b'-' | b'_'))
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/4de44c90bc3b55db. Report an issue: GitHub.

Appendix: source

Thrown at src/system/firewall.rs:2033

fn command_error(program: &str, args: &[&str], output: &Output) -> eyre::Report {
    eyre!(
        "{} failed with {}: {}",
        shell_words::join(
            std::iter::once(program.to_string()).chain(args.iter().map(|arg| (*arg).to_string()))
        ),
        output.status,
        String::from_utf8_lossy(&output.stderr).trim()
    )
}

fn validate_name(name: &str) -> Result<()> {
    if name.is_empty()
        || name.len() > 64
        || !name
            .bytes()
            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_'))
    {
        bail!("firewall rule name '{name}' must contain only ASCII letters, numbers, '-' or '_'");
    }
    Ok(())
}

fn validate_interface(interface: &str) -> Result<String> {
    if interface.is_empty()
        || interface.len() > 15
        || !interface
            .bytes()
            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_' | b'.' | b':'))
    {
        bail!("firewall interface '{interface}' is invalid");
    }
    Ok(interface.to_string())
}

fn parse_ssh_connection(value: &str) -> Result<SshConnection> {
    let fields = value.split_ascii_whitespace().collect::<Vec<_>>();

View on GitHub (pinned to 533346cc37)