jdx/mise · warning

another history operation is running

Error message

another history operation is running

What it means

Contention failure in acquire_operation_lock: another history operation (e.g. the watcher applying incoming changes) holds the operation lock in the state dir and did not release it within the bounded wait, so the new operation refuses to proceed to avoid concurrent mutation.

Source

Thrown at src/system/history/scope.rs:704

    let path = store::operation_lock_in(state_dir);
    // a running operation (the watcher applying incoming changes, say) is
    // usually over in moments: wait for it a bounded while before failing
    let deadline = std::time::Instant::now() + wait;
    let mut announced = false;
    let lock = loop {
        if let Some(lock) = LockFile::new(&path).try_lock()? {
            break lock;
        }
        let marker = store::read_marker_in(state_dir)?;
        if std::time::Instant::now() >= deadline {
            match marker {
                Some(marker) => bail!(
                    "another history operation is running: {} since {} ({})",
                    marker.kind.as_str(),
                    marker.started_at,
                    marker.command
                ),
                None => bail!("another history operation is running"),
            }
        }
        if !announced {
            announced = true;
            info!(
                "history: waiting for another history operation to finish{}",
                marker
                    .map(|marker| format!(": {} ({})", marker.kind.as_str(), marker.command))
                    .unwrap_or_default()
            );
        }
        std::thread::sleep(OPERATION_LOCK_POLL);
    };
    Ok(lock)
}

/// How long an operation waits for a running one, and how often it looks.
const OPERATION_LOCK_WAIT: std::time::Duration = std::time::Duration::from_secs(30);

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Wait and retry once the other operation finishes (it is usually brief)
  2. Check the state dir marker to identify the running operation and whether it is wedged
  3. Remove a stale lock only after confirming no history process is alive

Example fix

# find who holds the lock
lsof "$MISE_STATE_DIR"/history/lock
# if stale:
rm "$MISE_STATE_DIR"/history/lock
Defensive patterns

Strategy: retry

Try / catch

match history_op() {
    Err(e) if e.to_string().contains("another history operation is running") => {
        if lock_holder_dead() { remove_stale_lock(); retry(); } else { wait(); }
    }
    other => other,
}

Prevention

When it happens

Trigger: Lock held past deadline and store::read_marker_in returned None — the holder is an older/foreign process that did not write a marker, or the marker was deleted while the lock is held.

Common situations: Mixed mise versions sharing a state dir; marker file removed manually; lock held by a non-mise tool that created the same lock file.

Related errors


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