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
- Wait and retry once the other operation finishes (it is usually brief)
- Check the state dir marker to identify the running operation and whether it is wedged
- 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
- Use the same mise version everywhere so markers are always written
- Never manually delete marker files while operations may be live
- Use lsof to confirm a lock is stale before removing it
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
- another history operation is running: {} since {} ({})
- local saved history changed since planning; nothing was appl
- another setup sync or pull is running; retry shortly
- history changed during the operation; cannot replace its bef
- brew-cask:{}: Homebrew took ownership of this cask while ins
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/b61407e313a05f5d.
Report an issue: GitHub.