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
- Wait for the running operation to finish, then retry
- If the holder is dead (crashed/killed), remove the stale lock and marker from MISE_STATE_DIR and retry
- 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
- Don't run multiple mise history operations concurrently
- Give long waits an adequate deadline
- Check for crashed runs leaving locks before scripting operations
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
- another history operation is running
- appeared after was protected; nothing more was changed
- changed after it was protected; nothing more was changed
- history changed during the operation; cannot replace its…
- incoming application requires an active recovery operation
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)