{"record":{"id":"8117259a3ee5b510","repo":"astrid-runtime/astrid","slug":"no-loaded-capsule-handles-the-registry-request-for","errorCode":null,"errorMessage":"no loaded capsule handles the registry request for caller","messagePattern":"no loaded capsule handles the registry request for caller","errorType":"http","errorClass":"GatewayError::Internal","httpStatus":500,"severity":"error","filePath":"crates/astrid-gateway/src/routes/models.rs","lineNumber":321,"sourceCode":") -> GatewayResult<()> {\n    let Some(probe) = &state.topic_probe else {\n        return Err(GatewayError::Kernel(\n            \"gateway has no live capsule provider probe\".into(),\n        ));\n    };\n    let key = scoped_topic_probe_key(principal, request_topic);\n    if probe.is_subscribed(&key).await || probe.ensure_subscribed(&key).await {\n        return Ok(());\n    }\n\n    let timeout = state.registry_timeout.unwrap_or(REGISTRY_TIMEOUT);\n    let started = tokio::time::Instant::now();\n    loop {\n        if probe.is_subscribed(&key).await {\n            return Ok(());\n        }\n        if started.elapsed() >= timeout {\n            return Err(GatewayError::Internal(anyhow::anyhow!(\n                \"no loaded capsule handles the registry request for caller\"\n            )));\n        }\n        tokio::time::sleep(CAPSULE_PROBE_INTERVAL).await;\n    }\n}\n\nasync fn provider_source_ids(\n    state: &GatewayState,\n    principal: &PrincipalId,\n    request_topic: &str,\n) -> GatewayResult<Vec<Uuid>> {\n    let probe = state.topic_probe.as_ref().ok_or_else(|| {\n        GatewayError::Internal(anyhow::anyhow!(\n            \"gateway has no live capsule provider probe\"\n        ))\n    })?;\n    let key = scoped_topic_probe_key(principal, request_topic);","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-gateway/src/routes/models.rs#L303-L339","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check gateway startup logs for registry capsule load failures and reload the capsule.","Increase the probe timeout if the capsule legitimately takes longer to subscribe than the current budget.","Verify the subscription key derivation for the caller (principal/topic mapping) matches what the capsule subscribes to.","Confirm the capsule process is healthy and re-probe; restart the gateway if the capsule manager is wedged."],"exampleFix":"// before\nif started.elapsed() >= timeout {\n    return Err(GatewayError::Internal(anyhow::anyhow!(\n        \"no loaded capsule handles the registry request for caller\"\n    )));\n}\n// after\nif started.elapsed() >= timeout {\n    tracing::error!(%principal, %request_topic, ?timeout, \"registry capsule never subscribed\");\n    return Err(GatewayError::ServiceUnavailable(\n        \"model registry capsule is not available\".into(),\n    ));\n}","handlingStrategy":"validation","validationCode":"// before calling registry endpoints, check capsule readiness\nif !probe.is_subscribed(&registry_request_key(principal, request_topic)).await {\n    return Err(ServiceUnavailable(\"registry capsule not ready\"));\n}","typeGuard":"fn capsule_ready(probe: &CapsuleProbe, key: &str) -> bool {\n    // sync peek with a very short poll to avoid the full timeout path\n    probe.try_subscribed(key)\n}","tryCatchPattern":"match list_models(&state, caller).await {\n    Err(e) if e.message().contains(\"no loaded capsule handles the registry request\") => {\n        tracing::error!(\"registry capsule missing/not subscribed\");\n        StatusCode::SERVICE_UNAVAILABLE\n    }\n    r => r,\n}","preventionTips":["Gate model routes on a startup health check that the registry capsule loaded and subscribed.","Size the probe timeout above the capsule's worst-case warm-up time.","Fail fast and log loudly at capsule load failure instead of silently continuing.","Verify per-caller subscription key derivation against the capsule's own key computation in tests."],"tags":["capsule","registry","timeout","gateway"],"backgroundTag":"resource-not-found","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}