jdx/mise · error

Check command must not be empty

Error message

Check command must not be empty

What it means

Doctor project checks defined in project configuration must supply a non-empty `run` command. When a check's `run` field is missing, blank, or only whitespace, mise's doctor refuses to execute it and bails with this error, since running an empty shell command is meaningless.

Solutions

  1. Set a non-empty `run` command on the offending check in the project's mise/doctor configuration.
  2. Remove the empty check entry entirely if it is not needed.
  3. If the command comes from a template/variable, ensure that variable is defined and non-empty at render time.

Example fix

// before (mise.toml)
[[doctor.checks]]
name = "lint"
run = ""

// after
[[doctor.checks]]
name = "lint"
run = "npm run lint"
Defensive patterns

Strategy: validation

Validate before calling

// validate doctor check config before running mise doctor
for check in checks {
    if check.run.trim().is_empty() {
        panic!("doctor check '{}' has an empty run command", check.name);
    }
}

Prevention

When it happens

Trigger: A `mise doctor` project check where `check.run.trim().is_empty()` — i.e. the check entry has `run = ""`, `run = " "`, or omits `run` entirely while still being executed by run_check (called from check).

Common situations: Hand-editing doctor check config and leaving a placeholder empty `run`; templated config where a variable meant to hold the command expanded to empty; copy-pasting a check entry and forgetting to fill in the command.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/cli/doctor/project.rs:226

                }
            })
            // Unordered so a slow probe does not hold back admission of the
            // remaining checks; the report is sorted by name afterwards.
            .buffer_unordered(crate::jobs::normalize(Settings::get().jobs))
            .collect()
            .await;
        report.checks.sort_by(|a, b| a.name.cmp(&b.name));
        Ok(report)
    }
}

async fn run_check(
    check: &DoctorCheck,
    root: &Path,
    environment: &EnvMap,
) -> Result<std::process::Output> {
    if check.run.trim().is_empty() {
        bail!("Check command must not be empty");
    }
    let timeout = check
        .timeout
        .as_deref()
        .map(crate::duration::parse_duration)
        .transpose()?
        .unwrap_or(Duration::from_secs(10));
    if timeout.is_zero() {
        bail!("Check timeout must be greater than zero");
    }
    let mut shell = match &check.shell {
        Some(shell) => crate::path::split_shell_command(shell)?,
        None => Settings::get().default_inline_shell()?,
    };
    Settings::get().maybe_no_profile(&mut shell);
    let Some((program, args)) = shell
        .split_first()
        .filter(|(program, _)| !program.trim().is_empty())

View on GitHub (pinned to 533346cc37)