jdx/mise · error

repos: command is required

Error message

repos: command is required

What it means

The repos exec entry point splits the provided command slice into program + args; an empty command slice has no program to run, so exec bails with `repos: command is required` before touching any repos. The command is what gets run inside each configured repo checkout.

Solutions

  1. Supply a command, e.g. `mise repos exec -- git status`
  2. Check script variables so the command string is not empty at invocation time
  3. Verify flags (like `--`) ordering so the command tokens are not swallowed as flags

Example fix

# before
mise repos exec --
# after
mise repos exec -- git status
Defensive patterns

Strategy: validation

Validate before calling

[ -n "$CMD" ] || { echo "repos exec: command is required"; exit 1; }
mise repos exec -- $CMD

Try / catch

match result {
    Err(e) if e.to_string().contains("command is required") => {
        eprintln!("supply a command: mise repos exec -- <program> [args...]");
    }
    Err(e) => return Err(e),
    Ok(v) => v,
}

Prevention

When it happens

Trigger: Calling the repos exec path with `command = []` — e.g. `mise repos exec` with no command arguments supplied.

Common situations: Invoking the CLI without the command after flags; a script variable holding the command expanding to empty; mis-ordered flags causing the command tokens to be consumed elsewhere.

Understand the failure class

Background: "no subcommand specified" and "... is required": CLI errors when a required argument is missing — this error's family across 13 libraries.

Related errors


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

Appendix: source

Thrown at src/system/repos.rs:218

                update_unpinned_repo(&status.request, dry_run)?
            }
            RepoState::Current => {
                info!("repos: {} already current", status.request);
            }
            RepoState::Dirty | RepoState::Conflict(_) => unreachable!("preflighted above"),
        }
    }
    Ok(())
}

pub(crate) async fn exec(
    requests: &[RepoRequest],
    command: &[String],
    dry_run: bool,
    continue_on_error: bool,
) -> Result<()> {
    let Some((program, args)) = command.split_first() else {
        bail!("repos: command is required");
    };
    let statuses = status(requests).await?;
    let mut failures = vec![];
    for status in statuses {
        match &status.state {
            RepoState::Missing => {
                warn!("repos: {}: missing, skipping", status.request);
                continue;
            }
            RepoState::Conflict(reason) => {
                warn!("repos: {}: {reason}, skipping", status.request);
                continue;
            }
            RepoState::Current | RepoState::Differs | RepoState::Dirty => {}
        }

        miseprintln!("repo: {}", status.request);
        if dry_run {

View on GitHub (pinned to 533346cc37)