jdx/mise · error

config index exists

Error message

config index exists

What it means

mise panics with 'config index exists' in the bootstrap config sibling-insertion logic when `config_files.get_index(*index)` returns `None` for an index taken from `sibling_indices`. Those indices are recorded while iterating the same IndexMap, so they must remain valid; the panic means the map shrank or was rebuilt between recording the indices and using them for precedence-based insertion (`shift_insert` of a bootstrap config file).

Source

Thrown at src/config/mod.rs:1668

        config_files.insert(path, config_file);
        return;
    }

    let precedence = bootstrap_config_filename_precedence(&path);
    let sibling_indices = config_files
        .keys()
        .enumerate()
        .filter(|(_, existing)| existing.parent() == path.parent())
        .map(|(index, _)| index)
        .collect_vec();
    let index = sibling_indices
        .iter()
        .copied()
        .find(|index| {
            bootstrap_config_filename_precedence(
                config_files
                    .get_index(*index)
                    .expect("config index exists")
                    .0,
            ) < precedence
        })
        .or_else(|| sibling_indices.last().map(|index| index + 1))
        .unwrap_or(config_files.len());
    config_files.shift_insert(index, path, config_file);
}

fn bootstrap_config_filename_precedence(path: &Path) -> Option<usize> {
    DEFAULT_CONFIG_FILENAMES.iter().position(|candidate| {
        !is_glob_pattern(candidate) && Path::new(candidate).file_name() == path.file_name()
    })
}

fn configs_at_root<'a>(dir: &Path, config_files: &'a ConfigMap) -> Vec<&'a Arc<dyn ConfigFile>> {
    // Highest precedence config files are returned first.
    let mut configs: Vec<&'a Arc<dyn ConfigFile>> = DEFAULT_CONFIG_FILENAMES
        .iter()

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Recompute sibling indices immediately before the precedence lookup instead of caching them across mutations
  2. Verify no code path removes entries from `config_files` between index collection and `shift_insert`
  3. Add a bounds check and skip stale indices rather than panicking
  4. Reproduce with the layered config set that triggers sibling dedup to identify which mutation drops the entry

Example fix

// before
.find(|index| config_files.get_index(*index).expect("config index exists").0)
// after
.find(|index| config_files.get_index(*index).map(|(k, _)| k).is_some_and(|k| bootstrap_config_filename_precedence(k) < precedence))
Defensive patterns

Strategy: validation

Validate before calling

if config_files.get_index(i).is_none() { continue; } // skip stale sibling index

Type guard

fn valid_index(map: &ConfigFiles, i: usize) -> bool { i < map.len() }

Prevention

When it happens

Trigger: Running the bootstrap config-file ordering code when `config_files` is mutated (entries removed/merged) between collecting `sibling_indices` and the precedence `find` that dereferences them — e.g. layered config loading removes a file, or the index list was computed against a different map instance.

Common situations: Bootstrap `[config]` declarations referencing sibling config files that get deduplicated or dropped during layered load; env-specific config filtering shrinking the map mid-pass; refactors that reorder collection of sibling indices.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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