{"record":{"id":"a93174165402deaf","repo":"jdx/mise","slug":"expected-a-run-command","errorCode":null,"errorMessage":"expected a `run` command","messagePattern":"expected a `run` command","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/hooks.rs","lineNumber":90,"sourceCode":"        let Some(phase) = BootstrapHookPhase::parse(phase_raw) else {\n            let valid = BootstrapHookPhase::iter()\n                .map(|phase| phase.as_str())\n                .collect::<Vec<_>>();\n            bail!(\n                \"unknown bootstrap hook phase {phase_raw:?}; valid phases are: {}\",\n                valid.join(\", \")\n            );\n        };\n        let runs = match value {\n            toml::Value::String(run) => vec![run],\n            toml::Value::Array(values) => string_array(values, \"expected string commands\")?,\n            toml::Value::Table(mut table) => match table.remove(\"run\") {\n                Some(toml::Value::String(run)) => vec![run],\n                Some(toml::Value::Array(values)) => {\n                    string_array(values, \"expected `run` to contain string commands\")?\n                }\n                Some(_) => bail!(\"expected `run` to be a string or array of strings\"),\n                None => bail!(\"expected a `run` command\"),\n            },\n            _ => bail!(\"expected a string, array of strings, or table with `run`\"),\n        };\n        let hooks = runs\n            .into_iter()\n            .filter_map(|run| {\n                let run = run.trim().to_string();\n                if run.is_empty() {\n                    warn!(\"[bootstrap.hooks.{phase}]: empty command, ignoring entry\");\n                    None\n                } else {\n                    Some(Self { phase, run })\n                }\n            })\n            .collect();\n        Ok(hooks)\n    }\n}","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/hooks.rs#L72-L108","documentation":"In table form, a [bootstrap.hooks.<phase>] table must contain a run key; this error fires when the table exists but run is absent. Other keys that look equivalent (cmd, command, script) are not recognized, so a table using them is treated as having no run at all.","triggerScenarios":"Writing [bootstrap.hooks.final] with cmd = \"./notify.sh\" instead of run, or an empty [bootstrap.hooks.final] table with no keys.","commonSituations":"Using key names carried over from other hook systems; starting a table intending to add the command later; typos or capitalized variants (Run, RUN) that TOML treats as different keys.","solutions":["Add run = \"<command>\" (or run = [ ... ]) to the phase table","Rename unrecognized keys like cmd/command/script to run","If the phase needs no command, delete the empty table"],"exampleFix":"# before\n[bootstrap.hooks.final]\ncmd = \"./notify.sh\"\n\n# after\n[bootstrap.hooks.final]\nrun = \"./notify.sh\"","handlingStrategy":"validation","validationCode":"# every [bootstrap.hooks.<phase>] table must contain a run key\npython3 - <<'EOF'\nimport tomllib,sys\nc=tomllib.load(open('mise.toml','rb'))\nfor phase,v in (c.get('bootstrap',{}).get('hooks',{}) or {}).items():\n    if isinstance(v,dict) and 'run' not in v: sys.exit(f'hook phase {phase} missing run')\nEOF","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use exactly the key name run for hook commands","Delete half-finished hook tables instead of leaving them keyless","Watch for capitalized variants; TOML keys are case-sensitive"],"tags":["mise","bootstrap","hooks","toml","missing-key"],"backgroundTag":"missing-config-key","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}