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 diagnostic

View on GitHub (pinned to affd8760f4)

Solutions

  1. Verify the capsule actually emits its Ready signal after activation and that nothing blocks before it.
  2. Increase `readiness_timeout` (currently 500ms) if the capsule legitimately needs longer to become ready.
  3. Check for slow initialization inside the capsule (warm-up work that should be deferred post-ready).
  4. 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

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


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/0a5694079964ce25. Report an issue: GitHub.