{"record":{"id":"e4998d1bbe1a2121","repo":"astrid-runtime/astrid","slug":"failed-to-acquire-daemon-start-fence-error","errorCode":null,"errorMessage":"failed to acquire daemon start fence: {error}","messagePattern":"failed to acquire daemon start fence: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/daemon.rs","lineNumber":461,"sourceCode":"            {\n                use std::os::unix::fs::PermissionsExt;\n                std::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700))?;\n            }\n        }\n        let mut options = std::fs::OpenOptions::new();\n        options.read(true).write(true).create(true).truncate(false);\n        #[cfg(unix)]\n        {\n            use std::os::unix::fs::OpenOptionsExt;\n            options.mode(0o600);\n        }\n        let file = options.open(&path)?;\n        file.lock()?;\n        Ok(file)\n    })\n    .await\n    .context(\"daemon start fence task failed\")?\n    .map_err(|error| anyhow::anyhow!(\"failed to acquire daemon start fence: {error}\"))?;\n    Ok(Arc::new(file))\n}\n\n/// Admit a disposable runtime override before lifecycle code can resolve or\n/// mutate any path under it.\npub(crate) fn validate_runtime_admission() -> Result<()> {\n    let home = astrid_core::dirs::AstridHome::resolve()\n        .context(\"failed to resolve Astrid home for runtime admission\")?;\n    home.validate_run_dir()\n        .context(\"failed to validate ASTRID_RUN_DIR\")\n}\n\n/// Keep the start fence outside the home until the kernel admits its layout.\nfn daemon_start_fence_path(home: &astrid_core::dirs::AstridHome) -> std::path::PathBuf {\n    let digest = blake3::hash(home.root().to_string_lossy().as_bytes());\n    std::env::temp_dir()\n        .join(\"astrid-start-fences\")\n        .join(format!(\"{digest}.lock\"))","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/daemon.rs#L443-L479","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"let lock_path = home.runtime_dir().join(\"daemon.start.lock\");\nif let Ok(holders) = std::fs::read_to_string(format!(\"/proc/locks\")) {\n    // or use lsof in shell preflight\n}\n// shell preflight: fuser \"$ASTRID_HOME/runtime/daemon.start.lock\" && echo \"fence held\"","typeGuard":null,"tryCatchPattern":"match acquire_daemon_start_fence().await {\n    Err(e) if e.to_string().contains(\"failed to acquire daemon start fence\") => {\n        tokio::time::sleep(Duration::from_millis(500)).await;\n        acquire_daemon_start_fence().await // bounded retry\n    }\n    other => other,\n}","preventionTips":["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."],"tags":["daemon","file-lock","concurrency","cli"],"backgroundTag":"file-lock-contention","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}