astrid-runtime/astrid · error
daemon connection closed while waiting for the MCP broker…
Error message
daemon connection closed while waiting for the MCP broker for principal '{principal}' What it means
While waiting for the MCP broker, wait_for_broker_on reads frames from the daemon connection with a timeout. If the read returns None (EOF) — the daemon closed the connection before the broker answered — the loop aborts with this error instead of retrying forever on a dead socket.
Solutions
- Restart the daemon (`astrid daemon start` or equivalent) and re-run the readiness check.
- Retry the readiness command — this is typically transient if the daemon was restarting.
- Inspect daemon logs/journal for crash reasons (panic, OOM) and fix the underlying failure.
- Ensure nothing concurrently stops the gateway/daemon (e.g. a stray `astrid mcp stop` in scripts) during readiness waits.
Example fix
// before
let frame = match tokio::time::timeout_at(wake_at, io.read_raw_frame()).await {
Ok(Ok(None)) => bail!("daemon connection closed..."),
...
// after (caller-side retry)
for attempt in 0..3 {
match wait_for_broker(&mut io, principal, deadline).await {
Ok(()) => break,
Err(e) if attempt < 2 => { tokio::time::sleep(Duration::from_secs(1)).await; }
Err(e) => return Err(e),
}
} Defensive patterns
Strategy: retry
Validate before calling
// probe the daemon liveness before waiting on the broker
if astrid_core::local_transport::connect_outcome(&daemon_socket).await
!= ConnectOutcome::Connected { eprintln!("daemon not running; start it first"); } Try / catch
match wait_for_broker(&mut io, principal, timeout).await {
Err(e) if e.to_string().contains("daemon connection closed") => {
tokio::time::sleep(Duration::from_secs(1)).await;
// reconnect to the daemon and retry the readiness wait (bounded retries)
}
other => other?,
} Prevention
- Confirm the daemon is up and stable before readiness waits
- Prevent concurrent stop/restart scripts from dropping the daemon mid-check
- Watch daemon memory (OOM) and crash logs
- Use bounded reconnect-and-retry loops around readiness checks
When it happens
Trigger: During `astrid mcp ready` / wait_for_broker: the daemon process exits or drops the connection between probes, so read_raw_frame() yields Ok(None) before the deadline.
Common situations: Daemon crash or restart mid-readiness-check; daemon killed by OOM or an admin; connection dropped by an intermediary; connecting to a socket whose daemon just shut down after a stop command.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
- Connection failures: ECONNREFUSED, ECONNRESET, and friends — why connections get refused, reset, or dropped.
Related errors
- capsules are installed, but connecting to the selected…
- daemon closed guard uplink
- daemon connection closed before command result
- Failed to connect to daemon. Check logs
- Failed to connect to daemon
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/f568676771d96d17.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-cli/src/commands/mcp/readiness.rs:119
anyhow::bail!(
"MCP broker did not become ready for principal '{principal}' within {}s; no capsule answered {TOOLS_LIST_TOPIC}",
ready_deadline.as_secs()
);
}
if now >= retry_at {
debug!(%principal, "MCP broker readiness probe interval elapsed; retrying idempotent tools/list");
send_probe(io, principal, &mut outstanding).await?;
retry_at = Instant::now()
.checked_add(retry_interval)
.unwrap_or(deadline);
continue;
}
let wake_at = retry_at.min(deadline);
let frame = match tokio::time::timeout_at(wake_at, io.read_raw_frame()).await {
Ok(Ok(Some(frame))) => frame,
Ok(Ok(None)) => {
anyhow::bail!(
"daemon connection closed while waiting for the MCP broker for principal '{principal}'"
)
},
Ok(Err(error)) => {
return Err(error).with_context(|| {
format!(
"daemon connection failed while waiting for the MCP broker for principal '{principal}'"
)
});
},
Err(_) => {
if Instant::now() >= deadline {
anyhow::bail!(
"MCP broker did not become ready for principal '{principal}' within {}s; no capsule answered {TOOLS_LIST_TOPIC}",
ready_deadline.as_secs()
);
}
debug!(%principal, "MCP broker readiness probe unanswered; retrying idempotent tools/list");View on GitHub (pinned to affd8760f4)