astrid-runtime/astrid · error · GatewayError::Internal
unexpected response for GetAgentReadiness
Error message
unexpected response for GetAgentReadiness: {other:?} What it means
The gateway asked the daemon kernel for an agent's readiness status, but the kernel replied with a KernelResponse variant that is neither AgentReadiness nor Error. This is a protocol/programming bug between the gateway and kernel, not a user input problem. The gateway converts it into a GatewayError::Internal with the offending variant debug-printed.
Solutions
- Check that gateway and daemon-kernel versions match and rebuild/redeploy both from the same commit
- Inspect the printed {other:?} variant to identify which unexpected KernelResponse is being returned
- Verify the kernel handles GetAgentReadiness and replies with KernelResponse::AgentReadiness for that request id
- If reproducible, file/inspect the BusKernelClient reply-correlation logic for request/response id mismatch
Example fix
// before: mismatched versions cause stale response enum // after: pin both crates to the same workspace/version and rebuild cargo build -p astrid-gateway -p astrid-daemon-kernel
Defensive patterns
Strategy: try-catch
Validate before calling
match kernel_response {
KernelResponse::AgentReadiness(_) | KernelResponse::Error(_) => Ok(()),
other => Err(format!("kernel version mismatch: got {other:?} for GetAgentReadiness")),
} Type guard
fn is_agent_readiness(resp: &KernelResponse) -> bool {
matches!(resp, KernelResponse::AgentReadiness(_))
} Try / catch
match client.request(KernelRequest::GetAgentReadiness).await? {
KernelResponse::AgentReadiness(r) => Ok(r),
KernelResponse::Error(msg) => Err(GatewayError::Forbidden { reason: msg }),
other => { log::error!("kernel protocol mismatch: {other:?}"); Err(GatewayError::Internal(anyhow::anyhow!("unexpected response for GetAgentReadiness: {other:?}"))) }
} Prevention
- Deploy gateway and kernel from the same build so KernelResponse enums match
- Add a startup protocol/version handshake between gateway and kernel
- Write an integration test asserting AgentReadiness comes back for GetAgentReadiness
When it happens
Trigger: get_readiness() in crates/astrid-gateway/src/routes/system.rs sends KernelRequest::GetAgentReadiness and matches only KernelResponse::AgentReadiness(r) and KernelResponse::Error(msg); any other variant (e.g. Success(_), a mismatched reply from a different request type) hits the catch-all arm.
Common situations: A kernel upgrade changed the response enum and the gateway was not rebuilt; requests are being routed to the wrong kernel handler; a bus reply for a different request id is delivered to this awaiting caller due to a client-side multiplexing bug.
Related errors
- unexpected response for ReloadCapsules
- unexpected daemon metadata response
- unexpected distro lock response
- unexpected response while resolving principal UID
- daemon did not return an agent-readiness response
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/4195890760e13460.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-gateway/src/routes/system.rs:72
(status = 200, description = "`AgentLoopReadiness` JSON shape: `{ ready: bool, prompt_subscribers: [string], response_publishers: [string], unsatisfied_required_imports: [{ capsule, namespace, interface, requirement }], loaded_capsules: [string] }`. `ready` is false when the installed capsule set can't serve an agent chat turn.", content_type = "application/json"),
(status = 401, body = ErrorBody),
(status = 403, body = ErrorBody, description = "Caller lacks `capsule:list`."),
)
)]
pub async fn get_readiness(
State(state): State<Arc<GatewayState>>,
req: Request<axum::body::Body>,
) -> GatewayResult<Json<AgentLoopReadiness>> {
let caller = caller_from(&req)?.clone();
let client = state.kernel_client_for(&caller)?;
let resp = client
.request(KernelRequest::GetAgentReadiness)
.await
.map_err(daemon_kernel_error)?;
match resp {
KernelResponse::AgentReadiness(r) => Ok(Json(r)),
KernelResponse::Error(msg) => Err(GatewayError::Forbidden { reason: msg }),
other => Err(GatewayError::Internal(anyhow::anyhow!(
"unexpected response for GetAgentReadiness: {other:?}"
))),
}
}
#[utoipa::path(
post,
path = "/api/sys/capsules/reload",
tag = "system",
responses(
(status = 204, description = "Capsules reloaded."),
(status = 401, body = ErrorBody),
(status = 403, body = ErrorBody, description = "Caller lacks `capsule:reload`."),
)
)]
pub async fn reload_capsules(
State(state): State<Arc<GatewayState>>,
req: Request<axum::body::Body>,View on GitHub (pinned to affd8760f4)