{"record":{"id":"ccb1dfa0a5e4884d","repo":"astrid-runtime/astrid","slug":"bus-admin-request-timed-out-after-waiting-for","errorCode":null,"errorMessage":"bus admin request timed out after {:?} waiting for {want_response}","messagePattern":"bus admin request timed out after (.+?) waiting for (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/astrid-gateway/src/bus_admin.rs","lineNumber":149,"sourceCode":"        // bearer's key_id rides on every admin op so a paired device cannot\n        // exceed its scope (e.g. a use-only device's PairDeviceIssue is denied\n        // even though its principal holds `self:auth:pair`).\n        if let Some(key_id) = &self.device_key_id {\n            msg = msg.with_device_key_id(key_id.clone());\n        }\n        self.bus.publish(AstridEvent::Ipc {\n            metadata: EventMetadata::new(\"astrid-gateway::bus_admin\"),\n            message: msg,\n        });\n\n        let deadline = tokio::time::Instant::now()\n            .checked_add(self.timeout)\n            .unwrap_or_else(tokio::time::Instant::now);\n\n        loop {\n            let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());\n            if remaining.is_zero() {\n                return Err(anyhow!(\n                    \"bus admin request timed out after {:?} waiting for {want_response}\",\n                    self.timeout\n                ));\n            }\n            let event = match tokio::time::timeout(remaining, receiver.recv()).await {\n                Ok(Some(ev)) => ev,\n                Ok(None) => {\n                    return Err(anyhow!(\n                        \"event bus closed before response on {want_response}\"\n                    ));\n                },\n                Err(_) => {\n                    return Err(anyhow!(\n                        \"bus admin request timed out after {:?} waiting for {want_response}\",\n                        self.timeout\n                    ));\n                },\n            };","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-gateway/src/bus_admin.rs#L131-L167","documentation":"BusAdminClient::request publishes an admin request onto the internal event bus and waits for the matching response topic. If the deadline (self.timeout, overridable via with_timeout) elapses before a response event arrives, it returns this anyhow error naming the timeout and the response topic it was waiting on. It means the kernel handler never answered (or answered too slowly) for that admin operation.","triggerScenarios":"Calling BusAdminClient::request(kind) when the kernel-side handler for that AdminRequestKind is not running, is blocked, or takes longer than self.timeout; also when remaining is already zero on loop entry because the deadline passed before the first recv.","commonSituations":"Kernel service not started or crashed while gateway is up; timeout set too low (default too aggressive for slow ops like migration-heavy admin calls); event bus backpressure dropping or delaying the response publish; wrong request topic/response topic pairing after a refactor.","solutions":["Verify the kernel/admin dispatcher is running and subscribed to the request topic","Increase the timeout via BusAdminClient::with_timeout for slow admin operations","Check kernel logs for errors or panics in the handler for that AdminRequestKind","Confirm the handler publishes its response on response_topic(&kind) with the matching request_id"],"exampleFix":"// before\nlet client = BusAdminClient::new(&bus, caller);\nlet resp = client.request(AdminRequestKind::ListDevices).await?;\n// after\nlet client = BusAdminClient::new(&bus, caller).with_timeout(std::time::Duration::from_secs(30));\nlet resp = client.request(AdminRequestKind::ListDevices).await?;","handlingStrategy":"retry","validationCode":"// Before issuing, sanity-check the client timeout budget:\nfn has_adequate_timeout(c: &BusAdminClient, min: std::time::Duration) -> bool { /* compare configured timeout >= min via with_timeout construction */ true }","typeGuard":null,"tryCatchPattern":"match client.request(kind).await {\n    Ok(resp) => resp,\n    Err(e) if e.to_string().contains(\"timed out\") => {\n        // check kernel liveness, optionally retry with backoff and a larger timeout\n        retry_with_backoff(kind).await\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always construct the client with an explicit with_timeout appropriate to the operation","Add readiness checks confirming the kernel dispatcher is running before issuing admin ops","Add tracing on the request/response topics to observe handler latency"],"tags":["timeout","async","event-bus"],"backgroundTag":"request-timeout","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"}