{"record":{"id":"e9b3baa36ef7bbe5","repo":"jdx/mise","slug":"config-index-exists","errorCode":null,"errorMessage":"config index exists","messagePattern":"config index exists","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/config/mod.rs","lineNumber":1668,"sourceCode":"        config_files.insert(path, config_file);\n        return;\n    }\n\n    let precedence = bootstrap_config_filename_precedence(&path);\n    let sibling_indices = config_files\n        .keys()\n        .enumerate()\n        .filter(|(_, existing)| existing.parent() == path.parent())\n        .map(|(index, _)| index)\n        .collect_vec();\n    let index = sibling_indices\n        .iter()\n        .copied()\n        .find(|index| {\n            bootstrap_config_filename_precedence(\n                config_files\n                    .get_index(*index)\n                    .expect(\"config index exists\")\n                    .0,\n            ) < precedence\n        })\n        .or_else(|| sibling_indices.last().map(|index| index + 1))\n        .unwrap_or(config_files.len());\n    config_files.shift_insert(index, path, config_file);\n}\n\nfn bootstrap_config_filename_precedence(path: &Path) -> Option<usize> {\n    DEFAULT_CONFIG_FILENAMES.iter().position(|candidate| {\n        !is_glob_pattern(candidate) && Path::new(candidate).file_name() == path.file_name()\n    })\n}\n\nfn configs_at_root<'a>(dir: &Path, config_files: &'a ConfigMap) -> Vec<&'a Arc<dyn ConfigFile>> {\n    // Highest precedence config files are returned first.\n    let mut configs: Vec<&'a Arc<dyn ConfigFile>> = DEFAULT_CONFIG_FILENAMES\n        .iter()","sourceCodeStart":1650,"sourceCodeEnd":1686,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/config/mod.rs#L1650-L1686","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Recompute sibling indices immediately before the precedence lookup instead of caching them across mutations","Verify no code path removes entries from `config_files` between index collection and `shift_insert`","Add a bounds check and skip stale indices rather than panicking","Reproduce with the layered config set that triggers sibling dedup to identify which mutation drops the entry"],"exampleFix":"// before\n.find(|index| config_files.get_index(*index).expect(\"config index exists\").0)\n// after\n.find(|index| config_files.get_index(*index).map(|(k, _)| k).is_some_and(|k| bootstrap_config_filename_precedence(k) < precedence))","handlingStrategy":"validation","validationCode":"if config_files.get_index(i).is_none() { continue; } // skip stale sibling index","typeGuard":"fn valid_index(map: &ConfigFiles, i: usize) -> bool { i < map.len() }","tryCatchPattern":null,"preventionTips":["Recompute indices immediately before use rather than caching them","Avoid mutating the IndexMap between index collection and shift_insert","Check the map length before dereferencing cached indices"],"tags":["rust","config","bootstrap","indexmap","panic"],"backgroundTag":"internal-invariant-violation","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"}