jdx/mise · error

[daemons. ] requires preset when specifying version or…

Error message

[daemons.{name}] requires preset when specifying version or options

What it means

A `[daemons.<name>]` entry without a `preset` must be fully self-contained: it may not specify `version` or `options`, because those only make sense as inputs to a preset's expansion. If version or options appear without a preset, mise bails with this message during config load.

Solutions

  1. Add the intended `preset = "..."` key alongside version/options.
  2. Or remove the `version` and `options` keys and provide `run = "..."` directly.
  3. Check other declarations of the same daemon (merging layers) — one layer may set preset while yours sets only version/options.

Example fix

# before
[daemons.postgres]
version = "16"

# after (preset form)
[daemons.postgres]
preset = "postgres"
version = "16"

# or direct form
[daemons.postgres]
run = "postgres -D data"
Defensive patterns

Strategy: validation

Validate before calling

# shell: flag daemons with version/options but no preset
awk '/^\[daemons\./{blk=$0} /version|options/{if (blk !~ /preset/) print blk}' mise.toml

Prevention

When it happens

Trigger: Declaring `[daemons.foo]` with a `version` key and/or an `options` table but no `preset` key; the declaration is validated in `load` when the config is parsed (e.g. by task execution or env expansion).

Common situations: Users assuming `version`/`options` are generic daemon fields; converting a preset-based entry by deleting the `preset` line but leaving `version`; TOML examples copied from preset-based docs.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at src/daemons/mod.rs:98

                .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() {
                bail!("[daemons.{name}] requires run or preset");
            }
            if let Some(port) = table.get("port").and_then(toml::Value::as_integer) {
                if !(1..=65535).contains(&port) {
                    bail!("daemon port must be an integer from 1 to 65535");
                }
                table.insert(
                    "port".into(),
                    toml::Value::Table(toml::Table::from_iter([
                        (
                            "expect".into(),
                            toml::Value::Array(vec![toml::Value::Integer(port)]),
                        ),
                        ("bump".into(), toml::Value::Boolean(false)),
                    ])),
                );

View on GitHub (pinned to 533346cc37)