{"record":{"id":"dec48d3e38ef9c3b","repo":"jdx/mise","slug":"repos-command-is-required","errorCode":null,"errorMessage":"repos: command is required","messagePattern":"repos: command is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/repos.rs","lineNumber":215,"sourceCode":"                update_unpinned_repo(&status.request, dry_run)?\n            }\n            RepoState::Current => {\n                info!(\"repos: {} already current\", status.request);\n            }\n            RepoState::Dirty | RepoState::Conflict(_) => unreachable!(\"preflighted above\"),\n        }\n    }\n    Ok(())\n}\n\npub fn exec(\n    requests: &[RepoRequest],\n    command: &[String],\n    dry_run: bool,\n    continue_on_error: bool,\n) -> Result<()> {\n    let Some((program, args)) = command.split_first() else {\n        bail!(\"repos: command is required\");\n    };\n    let statuses = status(requests)?;\n    let mut failures = vec![];\n    for status in statuses {\n        match &status.state {\n            RepoState::Missing => {\n                warn!(\"repos: {}: missing, skipping\", status.request);\n                continue;\n            }\n            RepoState::Conflict(reason) => {\n                warn!(\"repos: {}: {reason}, skipping\", status.request);\n                continue;\n            }\n            RepoState::Current | RepoState::Differs | RepoState::Dirty => {}\n        }\n\n        miseprintln!(\"repo: {}\", status.request);\n        if dry_run {","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/repos.rs#L197-L233","documentation":"The repos exec command runs an arbitrary command inside each configured repo's directory. exec splits the command vec with split_first and requires at least a program name; an empty command list bails immediately with `repos: command is required` before any repo status is computed or any command runs.","triggerScenarios":"Invoking the repos exec CLI form with zero command arguments after the flags; a wrapper script passing an empty or unset variable expansion as the command.","commonSituations":"Shell scripts with unset variables (`... exec -- $EMPTY_VAR`); quoting mistakes that swallow the command word; CI steps parameterized by an env var that is empty on some runners.","solutions":["Pass at least a program name, e.g. `... exec -- git status`","In scripts, guard before invoking: `[ -n \"$CMD\" ] || { echo \"no command\" >&2; exit 1; }`"],"exampleFix":"# before\nCMD=\"\" ./run-repos.sh   # exec receives an empty command\n\n# after\n[ -n \"$CMD\" ] || CMD=\"git status\"\n./run-repos.sh","handlingStrategy":"validation","validationCode":"if command.is_empty() {\n    return Err(eyre::eyre!(\"no repos command given\"));\n}\n// or simply: ensure command.split_first().is_some() before calling repos::exec","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Default the command in wrapper scripts (`CMD=${CMD:-git status}`)","Fail fast in CI when the command variable is empty instead of passing it through"],"tags":["mise","bootstrap","repos","exec","cli"],"backgroundTag":"empty-command-argument","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}