atuinsh/atuin · error
timed out waiting for lock at
Error message
timed out waiting for lock at {} What it means
`wait_for_lock` awaits the pidfile flock with a timeout; if the timeout elapses (`outcome` is `Err(())`), it bails with 'timed out waiting for lock'. This happens when another process holds the lock for longer than the caller's timeout while trying to become the daemon or wait for the pidfile to become available.
Solutions
- Check whether the daemon process is alive and healthy (`pgrep -a atuin`, logs).
- Kill/stop a hung daemon (`pkill -9 atuin` if necessary) and retry.
- Increase any relevant daemon timeout settings or retry the command after a moment.
- Verify the pidfile is on a local filesystem (flock on NFS/network mounts is unreliable).
- Move to a separate ATUIN_HOME if another session's daemon owns the lock.
Example fix
# before atuin daemon # hangs, then: timed out waiting for lock at ... pkill -9 atuin # after pkill -9 atuin && atuin daemon # clear the stale lock holder first
Defensive patterns
Strategy: retry
Validate before calling
# verify lock holder is alive before waiting fuser -v ~/.local/share/atuin/daemon.pid 2>/dev/null || echo "no holder; safe to start"
Try / catch
match atuin::daemon::ensure_running() {
Err(e) if e.to_string().contains("timed out waiting for lock") => {
std::thread::sleep(Duration::from_secs(2));
retry_with_backoff(3);
}
Err(e) => return Err(e),
Ok(_) => {}
} Prevention
- Monitor daemon health so hung processes are detected early.
- Keep pidfiles on local filesystems, not NFS.
- Kill stale/hung daemons before retrying.
- Bound waits with retry + backoff in scripts.
When it happens
Trigger: `wait_for_pidfile_available` or `ensure_daemon_running` waiting on a pidfile whose owner process keeps the lock beyond the configured timeout — a hung/busy daemon, a deadlocked daemon, or heavy lock contention.
Common situations: Daemon startup stalled (e.g. slow bind, hung runtime) so the lock is never released or acquired; another user's daemon on a shared HOME; filesystem where flock behaves oddly (some network filesystems).
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- daemon already running
- `atuin history tail` requires Atuin to be built with the…
- daemon autostart is incompatible with…
- Daemon rejected shutdown request
- daemon sent a lag notice as a history event
AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19).
Data as JSON: /api/errors/dfb4254b138111fa.
Report an issue: GitHub.
Appendix: source
Thrown at crates/atuin/src/command/client/daemon.rs:214
let file = open_lock_file(path)?;
let outcome = Backoff::Linear(LOCK_POLL)
.retry_sync(
|| match file.try_lock() {
Ok(()) => ControlFlow::Break(Ok(())),
Err(TryLockError::WouldBlock) => ControlFlow::Continue(()),
Err(TryLockError::Error(err)) => {
ControlFlow::Break(Err(eyre!("could not lock {}: {err}", path.display())))
}
},
timeout,
)
.await;
match outcome {
Ok(Ok(())) => Ok(file),
Ok(Err(err)) => Err(err),
Err(()) => bail!("timed out waiting for lock at {}", path.display()),
}
}
async fn wait_for_pidfile_available(path: &Path, timeout: Duration) -> Result<()> {
let file = wait_for_lock(path, timeout).await?;
file.unlock().wrap_err_with(|| format!("failed to unlock {}", path.display()))?;
Ok(())
}
async fn connect_client(settings: &Settings) -> Result<HistoryClient> {
HistoryClient::new(
#[cfg(not(unix))]
settings.daemon.tcp_port,
#[cfg(unix)]
settings.daemon.existing_socket_path().into_owned(),
)
.await
}View on GitHub (pinned to 900007c480)