jdx/mise · error

[history] in {} is not a table

Error message

[history] in {} is not a table

What it means

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.

Source

Thrown at src/cli/dotfiles/track.rs:476

    r#"<bold><underline>Examples:</underline></bold>

    $ <bold>mise bootstrap dotfiles track ~/.zshrc ~/.config/hypr</bold>
    $ <bold>mise bootstrap dotfiles track ~/.zshrc --os macos</bold>
    $ <bold>mise bootstrap dotfiles track ~/.config/app/state.json --no-autosave</bold>
"#
);

/// Adds (or removes) a glob in `[history] exclude` of the global config.
/// Returns whether the file changed.
pub(crate) fn edit_exclude(glob: &str, add: bool) -> Result<bool> {
    use toml_edit::{Item, Value};
    let global = crate::config::global_shared_config_path();
    let mut doc = read_document(&global)?;
    let history = doc
        .entry("history")
        .or_insert(Item::Table(toml_edit::Table::new()));
    let Some(table) = history.as_table_mut() else {
        eyre::bail!("[history] in {} is not a table", display_path(&global));
    };
    table.set_implicit(false);
    let exclude = table
        .entry("exclude")
        .or_insert(Item::Value(Value::Array(toml_edit::Array::new())));
    let Some(array) = exclude.as_array_mut() else {
        eyre::bail!(
            "[history] exclude in {} is not an array",
            display_path(&global)
        );
    };
    let present = array.iter().any(|value| value.as_str() == Some(glob));
    let changed = if add && !present {
        array.push(Value::String(toml_edit::Formatted::new(glob.to_string())));
        true
    } else if !add && present {
        array.retain(|value| value.as_str() != Some(glob));
        true

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Open the global config file shown in the message and convert `history` to a table: `history = "x"` → `[history]\n…`
  2. Remove the stray `history` key if it is leftover garbage and rerun the exclude command
  3. Back up the config before editing; toml_edit refuses to overwrite wrong types by design

Example fix

// before (global config.toml)
history = "disabled"
// after
[history]
exclude = []
Defensive patterns

Strategy: validation

Validate before calling

# check the global config type before running
tomlq '.history | type' ~/.config/mise/config.toml   # must be "object"

Try / catch

mise dotfiles track --exclude <glob> || {
  grep -n '^history' ~/.config/mise/config.toml
}

Prevention

When it happens

Trigger: 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]`.

Common situations: 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.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/1127c5b173c37347. Report an issue: GitHub.