jdx/mise · error

another history operation is running

Error message

another history operation is running: {} since {} ({})

What it means

acquire_operation_lock tries a non-blocking lock on the history operation lockfile, polling until a deadline. On timeout it reads the store's progress marker and, if one exists, reports which operation kind, start time, and command holds the lock instead of failing silently.

Solutions

  1. Wait for the running operation to finish, then retry
  2. If the holder is dead (crashed/killed), remove the stale lock and marker from MISE_STATE_DIR and retry
  3. Increase the wait deadline or serialize history operations in scripts

Example fix

// before: concurrent runs
mise sync &
mise pull &
// after
mise sync && mise pull
Defensive patterns

Strategy: retry

Validate before calling

if history.operation_lock_held() {
    eprintln!("waiting for running history operation before starting");
}

Try / catch

match history.take_operation_lock_with_wait(deadline) {
    Err(e) if e.to_string().starts_with("another history operation is running") => {
        // surface marker info to user; retry after holder exits
        std::thread::sleep(Duration::from_secs(5));
        retry_with_longer_deadline()?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling take_operation_lock_with_wait or recovery_lock while another history operation holds the lock and the wait deadline expires; the marker exists in the state dir with the holder's kind/started_at/command.

Common situations: Two mise processes running history operations concurrently (e.g. two shells, an IDE integration plus CLI); a previous crashed run left the lock/marker; a long-running operation exceeding the wait timeout.

Related errors


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

Appendix: source

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

pub(crate) fn recovery_lock(store: &Store) -> Result<fslock::LockFile> {
    acquire_operation_lock(store, std::time::Duration::ZERO)
}

fn acquire_operation_lock(store: &Store, wait: std::time::Duration) -> Result<fslock::LockFile> {
    let state_dir = store.state_dir();
    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::at(&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);

View on GitHub (pinned to 533346cc37)