atuinsh/atuin · error
timed out waiting for lock at {}
Error message
timed out waiting for lock at {} What it means
wait_for_lock polls for a file lock on the daemon pidfile with a bounded timeout (via tokio::time::timeout around a blocking lock attempt). If the lock is not obtained before the deadline, the timeout elapses (Err(())) and the caller bails with 'timed out waiting for lock at <path>'.
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 c0c717ab04)
Solutions
- Retry after the blocking process exits — check `pgrep -f 'atuin daemon'` and wait for it to disappear.
- Kill the process holding the lock (`pkill -f 'atuin daemon'`) if it should not be running, then retry.
- Remove a stale pidfile only after confirming no daemon holds the lock, then restart.
- Avoid NFS/shared homes for ATUIN_HOME so flock semantics are reliable.
Example fix
// before pkill -f 'atuin daemon' ; atuin daemon start # may hit: timed out waiting for lock // after pkill -f 'atuin daemon'; while pgrep -f 'atuin daemon' >/dev/null; do sleep 0.2; done atuin daemon start
Defensive patterns
Strategy: retry
Validate before calling
for i in $(seq 1 20); do pgrep -f 'atuin daemon' >/dev/null || break; sleep 0.5; done atuin daemon start
Try / catch
loop {
match start_daemon().await {
Err(e) if e.to_string().contains("timed out waiting for lock") => continue_after_backoff(),
other => break other,
}
} Prevention
- Wait for the old daemon to fully exit before restarting.
- Keep ATUIN_HOME on a local filesystem, not NFS.
- Use systemd unit ordering/ExecStartPre checks when managing via systemd.
When it happens
Trigger: wait_for_pidfile_available or ensure_daemon_running waiting for another process to release the pidfile lock while it keeps holding it past the timeout duration (e.g. a long-lived daemon or a hung process).
Common situations: Restarting the daemon while the old one is slow to shut down; a wedged daemon holding the lock indefinitely; heavily loaded machine delaying daemon exit; NFS/network filesystems where flock behaves poorly.
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 (pidfile lock busy at {})
- daemon autostart is incompatible with `daemon.systemd_socket
- {message}
- {message}. Enable `daemon.autostart = true` or restart the d
- {reason}. Enable `daemon.autostart = true` or restart the da
AI-assisted analysis of atuinsh/atuin@c0c717ab04 (2026-09-12).
Data as JSON: /api/errors/dfb4254b138111fa.
Report an issue: GitHub.