astrid-runtime/astrid · error · GatewayError::Internal

no loaded capsule handles the registry request for caller

Error message

no loaded capsule handles the registry request for caller

What it means

`ensure_registry_request_subscribed` polls the capsule probe until a loaded capsule is subscribed to the caller's registry request topic. If the probe still reports no subscription after the configured timeout, it returns `GatewayError::Internal('no loaded capsule handles the registry request for caller')`. The model registry request can therefore never be answered for this caller.

Source

Thrown at crates/astrid-gateway/src/routes/models.rs:321

) -> GatewayResult<()> {
    let Some(probe) = &state.topic_probe else {
        return Err(GatewayError::Kernel(
            "gateway has no live capsule provider probe".into(),
        ));
    };
    let key = scoped_topic_probe_key(principal, request_topic);
    if probe.is_subscribed(&key).await || probe.ensure_subscribed(&key).await {
        return Ok(());
    }

    let timeout = state.registry_timeout.unwrap_or(REGISTRY_TIMEOUT);
    let started = tokio::time::Instant::now();
    loop {
        if probe.is_subscribed(&key).await {
            return Ok(());
        }
        if started.elapsed() >= timeout {
            return Err(GatewayError::Internal(anyhow::anyhow!(
                "no loaded capsule handles the registry request for caller"
            )));
        }
        tokio::time::sleep(CAPSULE_PROBE_INTERVAL).await;
    }
}

async fn provider_source_ids(
    state: &GatewayState,
    principal: &PrincipalId,
    request_topic: &str,
) -> GatewayResult<Vec<Uuid>> {
    let probe = state.topic_probe.as_ref().ok_or_else(|| {
        GatewayError::Internal(anyhow::anyhow!(
            "gateway has no live capsule provider probe"
        ))
    })?;
    let key = scoped_topic_probe_key(principal, request_topic);

View on GitHub (pinned to affd8760f4)

Solutions

  1. Check gateway startup logs for registry capsule load failures and reload the capsule.
  2. Increase the probe timeout if the capsule legitimately takes longer to subscribe than the current budget.
  3. Verify the subscription key derivation for the caller (principal/topic mapping) matches what the capsule subscribes to.
  4. Confirm the capsule process is healthy and re-probe; restart the gateway if the capsule manager is wedged.

Example fix

// before
if started.elapsed() >= timeout {
    return Err(GatewayError::Internal(anyhow::anyhow!(
        "no loaded capsule handles the registry request for caller"
    )));
}
// after
if started.elapsed() >= timeout {
    tracing::error!(%principal, %request_topic, ?timeout, "registry capsule never subscribed");
    return Err(GatewayError::ServiceUnavailable(
        "model registry capsule is not available".into(),
    ));
}
Defensive patterns

Strategy: validation

Validate before calling

// before calling registry endpoints, check capsule readiness
if !probe.is_subscribed(&registry_request_key(principal, request_topic)).await {
    return Err(ServiceUnavailable("registry capsule not ready"));
}

Type guard

fn capsule_ready(probe: &CapsuleProbe, key: &str) -> bool {
    // sync peek with a very short poll to avoid the full timeout path
    probe.try_subscribed(key)
}

Try / catch

match list_models(&state, caller).await {
    Err(e) if e.message().contains("no loaded capsule handles the registry request") => {
        tracing::error!("registry capsule missing/not subscribed");
        StatusCode::SERVICE_UNAVAILABLE
    }
    r => r,
}

Prevention

When it happens

Trigger: Calling any model registry endpoint when, after polling for `timeout` at `CAPSULE_PROBE_INTERVAL` intervals, no capsule is subscribed to the request topic key for the caller's principal — the registry capsule is missing, still loading, or subscribed under a different key.

Common situations: Registry capsule failed to load at gateway startup; capsule still warming up and the probe timeout is too short; per-caller subscription keys not established because the caller's identity/capsule mapping is wrong; capsule crashed after startup.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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