astrid-runtime/astrid · error
failed to acquire daemon start fence: {error}
Error message
failed to acquire daemon start fence: {error} What it means
Thrown by `acquire_daemon_start_fence` when the file-lock used as a daemon start fence (preventing concurrent daemon startup for the same home) cannot be acquired. The inner lock result is mapped into this error, so the concrete cause ({error}) is the underlying lock API's error — typically the lock being held elsewhere or an OS-level lock failure. Called from ensure_daemon_inner, handle_start, and handle_stop.
Source
Thrown at crates/astrid-cli/src/commands/daemon.rs:461
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700))?;
}
}
let mut options = std::fs::OpenOptions::new();
options.read(true).write(true).create(true).truncate(false);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
options.mode(0o600);
}
let file = options.open(&path)?;
file.lock()?;
Ok(file)
})
.await
.context("daemon start fence task failed")?
.map_err(|error| anyhow::anyhow!("failed to acquire daemon start fence: {error}"))?;
Ok(Arc::new(file))
}
/// Admit a disposable runtime override before lifecycle code can resolve or
/// mutate any path under it.
pub(crate) fn validate_runtime_admission() -> Result<()> {
let home = astrid_core::dirs::AstridHome::resolve()
.context("failed to resolve Astrid home for runtime admission")?;
home.validate_run_dir()
.context("failed to validate ASTRID_RUN_DIR")
}
/// Keep the start fence outside the home until the kernel admits its layout.
fn daemon_start_fence_path(home: &astrid_core::dirs::AstridHome) -> std::path::PathBuf {
let digest = blake3::hash(home.root().to_string_lossy().as_bytes());
std::env::temp_dir()
.join("astrid-start-fences")
.join(format!("{digest}.lock"))View on GitHub (pinned to affd8760f4)
Solutions
- Check whether another daemon is already running for this home (`astrid daemon status`) and don't start a second one.
- Identify the process holding the fence lock (`lsof`/`fuser` on the lock path under the home) and terminate it if stale.
- Wait and retry — the fence is held only transiently during start/stop.
- If the home is on NFS/unsupported fs, move ASTRID_HOME to a local filesystem.
Defensive patterns
Strategy: retry
Validate before calling
let lock_path = home.runtime_dir().join("daemon.start.lock");
if let Ok(holders) = std::fs::read_to_string(format!("/proc/locks")) {
// or use lsof in shell preflight
}
// shell preflight: fuser "$ASTRID_HOME/runtime/daemon.start.lock" && echo "fence held" Try / catch
match acquire_daemon_start_fence().await {
Err(e) if e.to_string().contains("failed to acquire daemon start fence") => {
tokio::time::sleep(Duration::from_millis(500)).await;
acquire_daemon_start_fence().await // bounded retry
}
other => other,
} Prevention
- Check `astrid daemon status` before issuing start/stop in scripts.
- Avoid concurrent `astrid daemon start` invocations for the same ASTRID_HOME.
- After a crash, kill leftover daemon processes before restarting.
- Keep the runtime directory on a local filesystem that supports flock.
When it happens
Trigger: Running `astrid daemon start`/`stop` (or ensure_daemon) while another process holds the fence lock file for the same Astrid home, or when the lock file is on a filesystem that doesn't support the lock operation (e.g. some network mounts).
Common situations: Two terminals starting the daemon simultaneously; a previous daemon died leaving a lock held by a stuck process; ASTRID_HOME on NFS where flock semantics fail.
Related errors
- shutdown stage daemon.singleton_lock: lock remains held at {
- unexpected env list response: {response:?}
- principal capsule removal must go through the authenticated
- Daemon returned an unexpected response to GetCommands
- Daemon exited prematurely ({status}).{}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/e4998d1bbe1a2121.
Report an issue: GitHub.