astrid-runtime/astrid · critical
Daemon exited prematurely ({status}).{}
Error message
Daemon exited prematurely ({status}).{} What it means
After the CLI spawns an (ephemeral) kernel daemon, it polls a readiness sentinel file until the daemon is ready or the spawn timeout elapses. If the child process terminates before signaling readiness, wait_for_ready reports ChildExited(status) and this error is raised, pointing the operator at the daemon's boot log via log_hint(). It means the daemon failed to boot at all rather than merely being slow.
Source
Thrown at crates/astrid-cli/src/commands/daemon.rs:128
.stderr(stderr);
// Remove stale readiness file before spawning so we don't
// mistake a leftover from a crashed daemon for the new one.
let _ = std::fs::remove_file(ready_path);
let mut child = cmd
.spawn()
.context("Failed to spawn background Kernel daemon")?;
// Poll for the readiness sentinel instead of the socket file.
// The readiness file is written only after load_all_capsules()
// completes (including await_capsule_readiness()), so the accept
// loop is guaranteed to be running by the time we connect.
let timeout_secs = configured_spawn_timeout_secs(workspace_root);
match wait_for_ready(ready_path, &mut child, timeout_secs).await {
ReadyWaitOutcome::Ready => Ok(child),
ReadyWaitOutcome::ChildExited(status) => {
anyhow::bail!("Daemon exited prematurely ({status}).{}", log_hint());
},
ReadyWaitOutcome::StillRunning => {
// Do not SIGKILL a live first cutover (layout-1 audit import
// can outlive the wait). Disown and tell the operator.
disown_if_still_running(child);
anyhow::bail!(
"Daemon is still starting after {timeout_secs} seconds; it was left running. Check logs or run `astrid status` / retry later.{}",
log_hint()
);
},
}
}
fn ephemeral_daemon_command(daemon_bin: &Path, workspace_root: &Path) -> std::process::Command {
let mut cmd = std::process::Command::new(daemon_bin);
cmd.arg("--ephemeral")
.arg("--workspace")
.arg(workspace_root)View on GitHub (pinned to affd8760f4)
Solutions
- Read the daemon boot log (see the log hint appended to the message) for the actual panic/error at exit.
- Run `astrid status` / check for a live daemon or leftover PID file; run `astrid restart` to clean stale endpoints and PID files.
- Verify the workspace path exists and is writable, and that ASTRID_WORKSPACE_STATE_DIR matches the expected layout.
- Rebuild/reinstall the daemon binary so CLI and daemon versions match, then retry.
Example fix
# before $ astrid daemon start Error: Daemon exited prematurely (exit status: 101). # after: diagnose from the boot log $ cat ~/.local/state/astrid/daemon-boot.log $ astrid restart $ astrid daemon start # OK
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight checks before spawning the daemon
fn preflight_daemon(workspace_root: &Path) -> anyhow::Result<()> {
anyhow::ensure!(workspace_root.is_dir(), "workspace does not exist: {}", workspace_root.display());
let pid_alive = recorded_daemon_pid_is_alive();
anyhow::ensure!(!pid_alive, "daemon already recorded as running; run `astrid restart`");
Ok(())
} Try / catch
match spawn_daemon_inner(ready_path, announce, None).await {
Err(e) if e.to_string().contains("exited prematurely") => {
let log = std::fs::read_to_string(boot_log_path()).unwrap_or_default();
eprintln!("daemon boot failed; log tail:\n{}", last_lines(&log, 20));
// clean up stale endpoint/PID then retry once
astrid_core::local_transport::remove_stale_endpoint(&socket_path)?;
spawn_daemon_inner(ready_path, announce, None).await
},
other => other,
} Prevention
- Read the daemon boot log immediately after this error — it names the real cause.
- Clean stale sockets/PID files with `astrid restart` after any unclean shutdown.
- Validate the workspace path and ASTRID_WORKSPACE_STATE_DIR before booting.
- Keep daemon and CLI binaries version-matched in your install pipeline.
When it happens
Trigger: spawn_daemon -> spawn_daemon_inner spawning `astrid-daemon --ephemeral --workspace <root>` and the child exits before writing the readiness file — lock contention, panic before tracing init, bad workspace path, incompatible state layout, or a missing/corrupt data dir.
Common situations: Another daemon holds the singleton lock and died leaving inconsistent state; workspace path doesn't exist or lacks permissions; daemon binary version incompatible with on-disk layout; port/socket path conflicts; corrupted audit/state files failing import at boot.
Related errors
- unexpected env list response: {response:?}
- principal capsule removal must go through the authenticated
- Daemon returned an unexpected response to GetCommands
- Daemon is still starting after {timeout_secs} seconds; it wa
- an Astrid daemon appears to be running but its uplink is unr
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/9fc5d0bb0bd9486a.
Report an issue: GitHub.