jdx/mise · error

pending inline overlays should be present

Error message

pending inline overlays should be present

What it means

mise panics with 'pending inline overlays should be present' when merging inline task overlays: `shift_remove(&t.name)` is called only after `pending_inline_overlays.contains_key(&t.name)` returned true in the same iteration, yet the remove still returns `None`. Since no mutation happens between the check and the remove, this indicates a logic break in the overlay bookkeeping (duplicate task names triggering the merge path with an inconsistent map).

Source

Thrown at src/config/mod.rs:4681

/// When the same name appears in more than one file task (e.g. a local
/// `.mise/tasks` script and a same-named task from a `git::` include), the last
/// one wins. Callers load `file_tasks` in declared `task_config.includes`
/// order, so the later include in the list takes precedence — see
/// `load_tasks_in_dir`.
fn merge_file_and_config_tasks(file_tasks: Vec<Task>, config_tasks: Vec<Task>) -> Vec<Task> {
    let mut by_name: IndexMap<String, Task> = IndexMap::new();
    for t in prefer_windows_file_task_siblings(file_tasks) {
        by_name.insert(t.name.clone(), t);
    }
    let mut seen_config_task_names = BTreeSet::new();
    let mut pending_inline_overlays: IndexMap<String, Vec<Task>> = IndexMap::new();
    for t in config_tasks {
        if !seen_config_task_names.insert(t.name.clone()) {
            let has_command = !t.run.is_empty() || !t.run_windows.is_empty() || t.file.is_some();
            if pending_inline_overlays.contains_key(&t.name) && has_command {
                let overlays = pending_inline_overlays
                    .shift_remove(&t.name)
                    .expect("pending inline overlays should be present");
                let mut base = t;
                for overlay in overlays.into_iter().rev() {
                    base.merge_toml_overlay(overlay);
                }
                by_name.insert(base.name.clone(), base);
            } else if let Some(overlays) = pending_inline_overlays.get_mut(&t.name) {
                overlays.push(t);
            }
            continue;
        }
        if let Some(existing) = by_name
            .get_mut(&t.name)
            .filter(|existing| existing.is_toml_include)
        {
            if t.config_precedence <= existing.config_precedence {
                if t.run.is_empty() && t.run_windows.is_empty() && t.file.is_none() {
                    existing.merge_toml_overlay(t);
                } else {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Use `shift_remove` directly and branch on its return value instead of a separate `contains_key` check
  2. Verify each name enters the merge branch at most once (track processed names)
  3. Confirm overlay map keys use exactly the same task-name string as `t.name`
  4. Reproduce with two duplicate inline task definitions to see which iteration removes the entry

Example fix

// before
if pending_inline_overlays.contains_key(&t.name) && has_command {
    let overlays = pending_inline_overlays.shift_remove(&t.name)
        .expect("pending inline overlays should be present");
// after
if has_command {
    if let Some(overlays) = pending_inline_overlays.shift_remove(&t.name) {
        // merge overlays
    }
Defensive patterns

Strategy: type-guard

Validate before calling

let Some(overlays) = pending_inline_overlays.shift_remove(&t.name) else { continue; };

Type guard

pending_inline_overlays.contains_key(&t.name)

Prevention

When it happens

Trigger: Duplicate task names in `config_tasks` where a task has a command (`run`/`run_windows`/`file`) and its name is in `pending_inline_overlays`, but the remove finds nothing — e.g. the name was already removed by an earlier iteration of the same loop processing another duplicate, or the map keys diverge from task names due to normalization.

Common situations: Configs defining the same inline task name multiple times (same file or across layered files) so the seen-set insert fails repeatedly; name normalization (path prefixes, case) making `contains_key` and `shift_remove` disagree; refactors of the overlay-merge loop.

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/df575e64aa171277. Report an issue: GitHub.