jdx/mise · error

exited with

Error message

exited with {status}

What it means

run_with_limits requires the describe command to exit successfully; a non-zero status means the description could not be produced reliably, so mise bails with 'exited with <status>'. The status string (e.g. 'exit status 1' or a signal description) is included to aid debugging.

Solutions

  1. Run the describe command manually to reproduce the non-zero exit and fix the underlying failure
  2. Make the describe script resilient: handle missing inputs and end with an explicit `exit 0` when it produced a usable (possibly empty) description
  3. Check the reported status for signals (e.g. 'signal: killed') pointing at OOM or external kills rather than a script bug

Example fix

# before: fails when the file is missing
describe.sh: cat /path/maybe-missing.txt

# after
describe.sh: cat /path/maybe-missing.txt 2>/dev/null || echo "(no description)"
Defensive patterns

Strategy: try-catch

Validate before calling

describe-command >/dev/null 2>&1 && echo ok || echo "describe command exits non-zero ($?); fix it before use" >&2

Try / catch

match history::describe() {
    Err(e) if e.to_string().starts_with("exited with") => {
        // log the status; fall back to a default description or fix the command
    }
    r => r?,
}

Prevention

When it happens

Trigger: The configured describe command's shell exits with a non-zero code or is killed by a signal during a history describe operation.

Common situations: Describe scripts with bugs (unset variables under `set -e`, failing subcommands); the command depends on files or env vars missing in the execution context; the shell was OOM-killed or signaled.

Related errors


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

Appendix: source

Thrown at src/system/history/describe_command.rs:182

            // with the last writer of the pipe, so it is not waited for
            active.0.kill();
            let _ = child.kill();
            let _ = child.wait();
            bail!("took longer than {}s", timeout.as_secs());
        }
        std::thread::sleep(Duration::from_millis(100));
    };
    // a descendant that outlived the shell and kept the pipe is not the
    // shell's answer: the output is waited for a moment, not forever
    let Ok(output) = receiver.recv_timeout(output_grace) else {
        active.0.kill();
        bail!("a process it started kept its output open");
    };
    if output.len() > DIFF_LIMIT {
        bail!("description output exceeded {} bytes", DIFF_LIMIT);
    }
    if !status.success() {
        bail!("exited with {status}");
    }
    let Some(line) = first_line(&output) else {
        return Ok(None);
    };
    annotate(
        store,
        entry,
        Annotation {
            description: Some(line.clone()),
            description_source: Some(DescriptionSource::Command),
            labels: None,
            updated_at: store::now_rfc3339(),
        },
    )?;
    Ok(Some(line))
}

/// The first non-empty line, trimmed, cut at the limit.

View on GitHub (pinned to 533346cc37)