atuinsh/atuin · error
daemon already running (pidfile lock busy at {})
Error message
daemon already running (pidfile lock busy at {}) What it means
The daemon uses an flock on a pidfile as a single-instance lock. acquire() tries a non-blocking lock; if it returns WouldBlock, another daemon process holds the lock, so this invocation aborts with the pidfile path in the message. It is the daemon's mutual-exclusion mechanism, not a filesystem permission problem.
Source
Thrown at crates/atuin/src/command/client/daemon.rs:119
const DAEMON_VERSION: &str = env!("CARGO_PKG_VERSION");
const DAEMON_PROTOCOL_VERSION: u32 = 2;
const STARTUP_POLL: Duration = Duration::from_millis(40);
const LOCK_POLL: Duration = Duration::from_millis(20);
const LEGACY_DAEMON_RESTART_MESSAGE: &str = "legacy daemon detected; restart daemon manually";
struct PidfileGuard {
file: File,
}
impl PidfileGuard {
fn acquire(path: &Path) -> Result<Self> {
let mut file = open_lock_file(path)?;
match file.try_lock() {
Ok(()) => {}
Err(TryLockError::WouldBlock) => {
bail!("daemon already running (pidfile lock busy at {})", path.display())
}
Err(TryLockError::Error(err)) => {
return Err(err)
.wrap_err_with(|| format!("could not lock daemon pidfile {}", path.display()));
}
}
file.set_len(0)
.wrap_err_with(|| format!("could not truncate daemon pidfile {}", path.display()))?;
writeln!(file, "{}", std::process::id())
.and_then(|()| writeln!(file, "{DAEMON_VERSION}"))
.wrap_err_with(|| format!("could not write daemon pidfile {}", path.display()))?;
Ok(Self { file })
}
}
impl Drop for PidfileGuard {View on GitHub (pinned to c0c717ab04)
Solutions
- Do nothing — the already-running daemon is the one to use; verify with `atuin daemon status` or `pgrep atuin`.
- If the old daemon is stale/unreachable, kill it (`pkill -f 'atuin daemon'`), confirm the pidfile lock is released, then restart.
- Point conflicting instances at separate ATUIN_HOME directories if you intentionally need multiple daemons.
- Prefer `atuin daemon start`/autostart over manual spawns so the lock logic is respected.
Example fix
// before atuin daemon start # error: daemon already running (pidfile lock busy at ...) // after atuin status # or just use the CLI; existing daemon serves requests
Defensive patterns
Strategy: try-catch
Validate before calling
pgrep -f 'atuin daemon' >/dev/null || atuin daemon start
Try / catch
match atuin_daemon_start().await {
Err(e) if e.to_string().contains("pidfile lock busy") => { /* daemon already running: proceed, it will serve us */ }
Err(e) => return Err(e),
Ok(()) => {}
} Prevention
- Let atuin autostart manage the daemon instead of starting it manually.
- One daemon per ATUIN_HOME; use separate homes for isolated instances.
- In systemd setups, only the unit should start the daemon.
When it happens
Trigger: Starting `atuin daemon` (or a command that spawns it, e.g. with autostart) while another atuin daemon instance is already running and holding the lock on the pidfile (typically ~/.local/share/atuin/daemon.pid).
Common situations: Double-starting the daemon manually; systemd socket units racing an autostart; a previous daemon still alive in another session/container sharing the same home directory; testing daemons in CI against a shared HOME.
Related errors
- timed out waiting for lock 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/89afabce7b80b742.
Report an issue: GitHub.