{"record":{"id":"1127c5b173c37347","repo":"jdx/mise","slug":"history-in-is-not-a-table","errorCode":null,"errorMessage":"[history] in {} is not a table","messagePattern":"\\[history\\] in (.+?) is not a table","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/dotfiles/track.rs","lineNumber":476,"sourceCode":"    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise bootstrap dotfiles track ~/.zshrc ~/.config/hypr</bold>\n    $ <bold>mise bootstrap dotfiles track ~/.zshrc --os macos</bold>\n    $ <bold>mise bootstrap dotfiles track ~/.config/app/state.json --no-autosave</bold>\n\"#\n);\n\n/// Adds (or removes) a glob in `[history] exclude` of the global config.\n/// Returns whether the file changed.\npub(crate) fn edit_exclude(glob: &str, add: bool) -> Result<bool> {\n    use toml_edit::{Item, Value};\n    let global = crate::config::global_shared_config_path();\n    let mut doc = read_document(&global)?;\n    let history = doc\n        .entry(\"history\")\n        .or_insert(Item::Table(toml_edit::Table::new()));\n    let Some(table) = history.as_table_mut() else {\n        eyre::bail!(\"[history] in {} is not a table\", display_path(&global));\n    };\n    table.set_implicit(false);\n    let exclude = table\n        .entry(\"exclude\")\n        .or_insert(Item::Value(Value::Array(toml_edit::Array::new())));\n    let Some(array) = exclude.as_array_mut() else {\n        eyre::bail!(\n            \"[history] exclude in {} is not an array\",\n            display_path(&global)\n        );\n    };\n    let present = array.iter().any(|value| value.as_str() == Some(glob));\n    let changed = if add && !present {\n        array.push(Value::String(toml_edit::Formatted::new(glob.to_string())));\n        true\n    } else if !add && present {\n        array.retain(|value| value.as_str() != Some(glob));\n        true","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/cli/dotfiles/track.rs#L458-L494","documentation":"edit_exclude opens the global shared config (toml_edit Document) to append an entry under [history]. If a [history] key exists but holds a non-table value (e.g. a string or array), the code cannot insert an exclude list and bails. This guards against corrupting an unexpectedly typed config section.","triggerScenarios":"Running `mise dotfiles track --exclude <glob>` (or untrack --exclude) when the global config file defines `history` as a scalar/array, e.g. `history = \"foo\"` instead of `[history]`.","commonSituations":"Hand-edited global config.toml that accidentally made history a value; a tool or older version wrote history as a string; copy-paste merging collisions in the global config.","solutions":["Open the global config file shown in the message and convert `history` to a table: `history = \"x\"` → `[history]\\n…`","Remove the stray `history` key if it is leftover garbage and rerun the exclude command","Back up the config before editing; toml_edit refuses to overwrite wrong types by design"],"exampleFix":"// before (global config.toml)\nhistory = \"disabled\"\n// after\n[history]\nexclude = []","handlingStrategy":"validation","validationCode":"# check the global config type before running\ntomlq '.history | type' ~/.config/mise/config.toml   # must be \"object\"","typeGuard":null,"tryCatchPattern":"mise dotfiles track --exclude <glob> || {\n  grep -n '^history' ~/.config/mise/config.toml\n}","preventionTips":["Never assign a scalar to `history` in the global config","Validate config.toml with a TOML linter after hand edits","Keep [history] as a table with exclude as an array"],"tags":["config","toml","dotfiles","type-mismatch"],"backgroundTag":"config-type-mismatch","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}