jdx/mise · error

invalid daemon name ; use letters, numbers, '.', '_' or

Error message

invalid daemon name {name:?}; use letters, numbers, '.', '_' or '-'

What it means

Daemon declarations in `[daemons.<name>]` must have names made only of ASCII letters, digits, '_', '-', and '.', and must not start or end with '-'. The `load` function validates each daemon name and bails with this message for anything else. This keeps daemon names usable as identifiers/process labels.

Solutions

  1. Rename the daemon key to only use letters, numbers, '.', '_' or '-'.
  2. Remove leading/trailing hyphens from the key.
  3. If the name comes from templating or a variable, sanitize it before writing the config.

Example fix

# before (mise.toml)
[daemons."my api"]
run = "python server.py"

# after
[daemons.my_api]
run = "python server.py"
Defensive patterns

Strategy: validation

Validate before calling

# shell: validate daemon names in mise.toml before running mise
grep -E '^\[daemons\.[^]]+\]' mise.toml | grep -vE '^\[daemons\.[A-Za-z0-9_.-]+\]$' && echo "invalid daemon name"

Prevention

When it happens

Trigger: Declaring a daemon in mise.toml whose table key contains spaces, slashes, non-ASCII characters, or starts/ends with '-', parsed during config load (load is invoked by task/env expansion paths such as daemons_merge_before_expanding_tools_and_exports).

Common situations: Copy-pasting a service name like `my daemon` or `api/server` into a `[daemons.*]` key; trailing hyphens from templated names; quoting mistakes in TOML keys.

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/d3b1a779851ae90b. Report an issue: GitHub.

Appendix: source

Thrown at src/daemons/mod.rs:82

                    cf.get_path().to_path_buf(),
                    cf.project_root().unwrap_or_else(|| cf.config_root()),
                ),
            );
        }
    }
    let mut set = DaemonSet::default();
    for (name, (declaration, source, root)) in declarations {
        if name.is_empty()
            || name == "."
            || name.contains("..")
            || name.contains("--")
            || name.starts_with('-')
            || name.ends_with('-')
            || !name
                .chars()
                .all(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '-' | '.'))
        {
            bail!("invalid daemon name {name:?}; use letters, numbers, '.', '_' or '-'");
        }
        let (preset, version, mut table) = match declaration {
            Declaration::Preset(version) => (Some(name.clone()), Some(version), toml::Table::new()),
            Declaration::Definition(mut table) => {
                let preset = take_string(&mut table, "preset")?;
                let version = take_string(&mut table, "version")?;
                (preset, version, table)
            }
        };
        let daemon = if let Some(preset) = preset {
            let version = version
                .ok_or_else(|| eyre::eyre!("[daemons.{name}] requires version with preset"))?;
            presets::expand(&name, &preset, &version, table, &source, &root)?
        } else {
            if version.is_some() || table.contains_key("options") {
                bail!("[daemons.{name}] requires preset when specifying version or options");
            }
            if table.get("run").and_then(toml::Value::as_str).is_none() {

View on GitHub (pinned to 533346cc37)