{"record":{"id":"bc38dca73ab66d1c","repo":"jdx/mise","slug":"expected-a-string-array-of-strings-or-table-with","errorCode":null,"errorMessage":"expected a string, array of strings, or table with `run`","messagePattern":"expected a string, array of strings, or table with `run`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/hooks.rs","lineNumber":92,"sourceCode":"                .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}\n\nfn string_array(values: Vec<toml::Value>, message: &str) -> Result<Vec<String>> {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/hooks.rs#L74-L110","documentation":"Each value directly under [bootstrap.hooks] must be a string, an array of strings, or a table containing run. This error fires for any other TOML type at the top level of a phase entry — integer, float, or boolean — because none of those shapes can describe a command to run.","triggerScenarios":"Writing [bootstrap.hooks] final = 3, final = 1.5, or final = false (enable/disable style) instead of a command value.","commonSituations":"Enable-flag style configs (final = true) copied from tools with toggles; numeric placeholders left in templated configs; YAML-to-TOML conversions that dropped the command string.","solutions":["Replace the scalar with a command string: final = \"./finish.sh\"","Use an array for multiple commands: final = [\"a.sh\", \"b.sh\"]","Remove the key entirely if no hook is wanted for that phase"],"exampleFix":"# before\n[bootstrap.hooks]\nfinal = true\n\n# after\n[bootstrap.hooks]\nfinal = \"./finish.sh\"","handlingStrategy":"validation","validationCode":"python3 - <<'EOF'\nimport tomllib,sys\nc=tomllib.load(open('mise.toml','rb'))\nfor phase,v in (c.get('bootstrap',{}).get('hooks',{}) or {}).items():\n    if not isinstance(v,(str,list,dict)): sys.exit(f'hook phase {phase} is {type(v).__name__}, need string/array/table')\nEOF","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never use enable-flag scalars for hooks; hooks are commands","Use mise bootstrap as the config linter after every hooks edit","Beware YAML-to-TOML conversions that drop or coerce command values"],"tags":["mise","bootstrap","hooks","toml","type-mismatch"],"backgroundTag":"config-type-mismatch","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}