astrid-runtime/astrid · error
shutdown stage daemon.singleton_lock: failed to acquire {}:
Error message
shutdown stage daemon.singleton_lock: failed to acquire {}: {error} What it means
The sibling case of the singleton-lock shutdown stage: `try_lock()` failed with `TryLockError::Error(error)`, an actual OS error (as opposed to the lock simply being held). `cleanup_daemon_runtime_for_home` maps that error into this shutdown-stage message including the lock path and the underlying {error}. The runtime cleanup aborts because the singleton state cannot be verified as free.
Source
Thrown at crates/astrid-cli/src/commands/daemon.rs:898
let mut options = std::fs::OpenOptions::new();
options.read(true).write(true).create(true);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt as _;
options.mode(0o600);
}
let lock = options.open(&lock_path).with_context(|| {
format!(
"shutdown stage daemon.singleton_lock: open {}",
lock_path.display()
)
})?;
lock.try_lock().map_err(|error| match error {
std::fs::TryLockError::WouldBlock => anyhow::anyhow!(
"shutdown stage daemon.singleton_lock: lock remains held at {}",
lock_path.display()
),
std::fs::TryLockError::Error(error) => anyhow::anyhow!(
"shutdown stage daemon.singleton_lock: failed to acquire {}: {error}",
lock_path.display()
),
})?;
match astrid_core::local_transport::connect_outcome(socket_path)
.await
.context("shutdown stage daemon.listener_probe")?
{
astrid_core::local_transport::ConnectOutcome::Connected(_) => {
anyhow::bail!(
"shutdown stage daemon.listener_absence: endpoint remains live at {}",
socket_path.display()
);
},
astrid_core::local_transport::ConnectOutcome::Stale => {
astrid_core::local_transport::remove_stale_endpoint(socket_path).with_context(
|| {View on GitHub (pinned to affd8760f4)
Solutions
- Read the wrapped {error} for the concrete errno (ENOENT, EACCES, EROFS) and fix that condition.
- Restore permissions on the home's runtime directory: `chown -R` / `chmod u+rw` the lock path.
- Recreate the home runtime layout if the lock file was deleted, then retry stop/cleanup.
- If the filesystem went read-only, remount it read-write or move ASTRID_HOME to a healthy local disk.
Defensive patterns
Strategy: try-catch
Validate before calling
let lock_path = home.runtime_dir().join("daemon.singleton.lock");
let meta = std::fs::metadata(&lock_path)
.map_err(|e| anyhow!("singleton lock {} unreadable before cleanup: {e}", lock_path.display()))?;
if meta.permissions().readonly() {
return Err(anyhow!("singleton lock {} is read-only", lock_path.display()));
} Try / catch
match cleanup_daemon_runtime() {
Err(e) if e.to_string().contains("failed to acquire") => {
let cause = /* extract wrapped error */;
eprintln!("singleton lock acquire failed: {cause}; check permissions/mount state");
// do NOT force-remove markers; surface to the operator
}
other => other,
} Prevention
- Keep the daemon runtime directory writable by the daemon's user only.
- Never delete files under the daemon's runtime dir while it is running.
- Alert on filesystems going read-only (EROFS) for the ASTRID_HOME mount.
- Recreate the runtime layout after external cleaners remove lock files.
When it happens
Trigger: Cleanup runs but acquiring the singleton lock fails due to I/O problems: lock file deleted mid-flight, permission denied on the lock file, filesystem error, or an OS-level flock failure.
Common situations: Runtime directory permissions changed after daemon start; lock file removed by an external cleaner while the daemon runs; disk/full or read-only remount of the home filesystem.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- shutdown stage daemon.singleton_lock: lock remains held at {
- {primary:#}; additional shutdown failure: {secondary:#}
- shutdown stage daemon.shutdown_ack: rejected: {reason}
- shutdown stage daemon.shutdown_ack: unexpected response: {ot
- shutdown stage daemon.process_reap: shutdown was acknowledge
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/3a696385ad2ea255.
Report an issue: GitHub.