jdx/mise · error

collection updates require scalar or array values

Error message

collection updates require scalar or array values

What it means

`mise config` append/remove operations read the current value of a key as a collection to modify. The `values` helper accepts only a TOML array or a single scalar value; anything else — notably an inline table or nested structure — cannot be treated as a collection, so mise bails. Array-of-tables (nested table items) also fall into the rejected arm.

Solutions

  1. Only use append/remove on scalar or array-valued keys; edit table-valued keys by targeting their leaf scalar/array sub-keys
  2. Edit the nested table directly in mise.toml or via `mise config set <table>.<subkey> <value>`
  3. Restructure the config so the collection is a plain array instead of array-of-tables if collection ops are needed
  4. Use `mise config get <key>` first to inspect the value's shape before appending

Example fix

// before
$ mise config append env._ foo   # env._ is an array-of-tables -> rejected
// after
$ mise config set env.FILE /path/to/env   # target the scalar sub-key of the table
Defensive patterns

Strategy: type-guard

Validate before calling

v=$(mise config get "$key" 2>/dev/null); case "$v" in ''|'['*|"\""*|*.*.) ;; *) echo "$key is not scalar/array"; exit 1;; esac

Type guard

is_scalar_or_array() { v=$(mise config get "$1" 2>/dev/null); case "$v" in "["*|"\""*|"'"*|[0-9]*|true|false) return 0;; *) return 1;; esac; }

Try / catch

mise config append "$key" "$item" 2>&1 | grep -q 'scalar or array' && { echo "edit the table sub-keys of $key directly"; exit 1; }

Prevention

When it happens

Trigger: `mise config append <key> <item>` / `mise config remove <key> <item>` where the existing key holds a table/inline-table (e.g. `[tools.node]` section or an array of tables `[[env._]]`), rather than a scalar or plain array.

Common situations: Trying to append to a key whose value is a nested table like `env.FOO.detail = ...`; appending to `[[some.table]]` array-of-tables entries; scripts assuming every config value is a list.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/fe271c9beec3e145. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/config/set.rs:253

        } else {
            table.insert(last_key, value);
        }

        let raw = config.to_string();
        MiseToml::from_str(&raw, &file)?;
        if let Some(parent) = file.parent() {
            std::fs::create_dir_all(parent)?;
        }
        std::fs::write(&file, raw)?;
        Ok(())
    }
}

fn values(item: toml_edit::Item) -> eyre::Result<Vec<toml_edit::Value>> {
    match item {
        toml_edit::Item::Value(toml_edit::Value::Array(array)) => Ok(array.into_iter().collect()),
        toml_edit::Item::Value(value) => Ok(vec![value]),
        _ => bail!("collection updates require scalar or array values"),
    }
}

fn values_equal(left: &toml_edit::Value, right: &toml_edit::Value) -> bool {
    if let (Some(left), Some(right)) = (left.as_str(), right.as_str()) {
        return left == right;
    }
    if let (Some(left), Some(right)) = (left.as_integer(), right.as_integer()) {
        return left == right;
    }
    if let (Some(left), Some(right)) = (left.as_float(), right.as_float()) {
        return left == right;
    }
    if let (Some(left), Some(right)) = (left.as_bool(), right.as_bool()) {
        return left == right;
    }
    if let (Some(left), Some(right)) = (left.as_datetime(), right.as_datetime()) {
        return left == right;

View on GitHub (pinned to 533346cc37)