astrid-runtime/astrid · error
candidate generation for '{id}' did not signal ready within
Error message
candidate generation for '{id}' did not signal ready within {}ms What it means
After a candidate generation activates successfully, the kernel waits `readiness_timeout` (500ms) via `candidate.wait_ready()` for the capsule to signal Ready. If the status returns `ReadyStatus::Timeout`, the kernel throws this error: the capsule is running but never reported readiness in time.
Source
Thrown at crates/astrid-kernel/src/lib.rs:4717
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
async fn activate_and_wait_ready(
id: &astrid_capsule_types::CapsuleId,
candidate: &mut dyn astrid_capsule::capsule::Capsule,
) -> Result<(), anyhow::Error> {
use astrid_capsule::capsule::ReadyStatus;
let activation_timeout = std::time::Duration::from_secs(30);
let readiness_timeout = std::time::Duration::from_millis(500);
match astrid_runtime::time::timeout(activation_timeout, candidate.activate()).await {
Ok(result) => result?,
Err(_) => anyhow::bail!(
"candidate generation for '{id}' did not activate within {}ms",
activation_timeout.as_millis()
),
}
match candidate.wait_ready(readiness_timeout).await {
ReadyStatus::Ready => Ok(()),
ReadyStatus::Timeout => anyhow::bail!(
"candidate generation for '{id}' did not signal ready within {}ms",
readiness_timeout.as_millis()
),
ReadyStatus::Crashed => {
anyhow::bail!("candidate generation for '{id}' exited before signaling ready")
},
}
}
/// Attempts to restart a failed capsule, respecting backoff and max retries.
///
/// Records ONE restart attempt (advancing backoff and the retry count) per call
/// when eligible. The count is a measure of CONSECUTIVE health failures: a busy
/// capsule whose restart legitimately leaves a lingering old instance is NOT
/// treated as a failure here — the tracker is pruned by the health monitor the
/// moment the capsule RECOVERS (see the retain in [`spawn_capsule_health_monitor`]),
/// so only a capsule that keeps failing across ticks accumulates toward the cap.
/// This deliberately does not key off the [`RestartOutcome`], which is diagnosticView on GitHub (pinned to affd8760f4)
Solutions
- Verify the capsule actually emits its Ready signal after activation and that nothing blocks before it.
- Increase `readiness_timeout` (currently 500ms) if the capsule legitimately needs longer to become ready.
- Check for slow initialization inside the capsule (warm-up work that should be deferred post-ready).
- Confirm the ready channel/IPC between capsule and kernel is functioning (no dropped signals).
Example fix
// before let readiness_timeout = std::time::Duration::from_millis(500); // after let readiness_timeout = std::time::Duration::from_millis(5000); // allow slow readiness probes
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: ensure the capsule's ready-signal path is wired before activation // assert candidate exposes a readiness channel and that init work is deferred past ready
Try / catch
match candidate.wait_ready(readiness_timeout).await {
ReadyStatus::Ready => Ok(()),
ReadyStatus::Timeout => { log::warn!("ready signal timeout"); /* backoff-retry */ }
ReadyStatus::Crashed => { /* handle crash */ }
} Prevention
- Signal Ready as early as possible in the capsule lifecycle; defer warm-up work
- Tune readiness_timeout (500ms default) to the capsule's real init time
- Test readiness signaling under load so signals aren't delayed past the window
When it happens
Trigger: `candidate.wait_ready(readiness_timeout)` returns `ReadyStatus::Timeout` — the capsule activated but its ready signal (e.g. health/ready handshake) was not observed within 500ms.
Common situations: Capsule's ready-signaling logic is delayed by slow init (cache warm-up, first request latency); readiness probe interval longer than the 500ms window; a bug where the capsule never calls the ready signal; flapping processes that activate but stall before signaling.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- timed out waiting for capsule command result
- daemon workspace metadata was not available within {timeout_
- MCP broker did not become ready for principal '{principal}'
- candidate generation for '{id}' did not activate within {}ms
- no loaded capsule handles the registry request for caller
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/0a5694079964ce25.
Report an issue: GitHub.