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

  1. Check whether the daemon process is alive and healthy (`pgrep -a atuin`, logs).
  2. Kill/stop a hung daemon (`pkill -9 atuin` if necessary) and retry.
  3. Increase any relevant daemon timeout settings or retry the command after a moment.
  4. Verify the pidfile is on a local filesystem (flock on NFS/network mounts is unreliable).
  5. 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

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.

Related errors


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)