{"record":{"id":"52c940a454cbcfea","repo":"astrid-runtime/astrid","slug":"gateway-is-not-wired-to-a-live-kernel-session-adm","errorCode":null,"errorMessage":"gateway is not wired to a live kernel session; admin operations unavailable","messagePattern":"gateway is not wired to a live kernel session; admin operations unavailable","errorType":"http","errorClass":"GatewayError::Internal","httpStatus":500,"severity":"error","filePath":"crates/astrid-gateway/src/state.rs","lineNumber":424,"sourceCode":"    /// shared event bus rather than the Unix socket — bypasses the\n    /// `astrid-capsule-cli` proxy entirely and removes the 19 RPS\n    /// admin-throughput ceiling the socket path imposes.\n    ///\n    /// # Errors\n    /// Returns an internal error if the state was built without a\n    /// live event bus (the standalone tests-only constructor). In\n    /// production the daemon always wires it up.\n    pub fn admin_client(\n        &self,\n        caller: astrid_core::PrincipalId,\n    ) -> Result<crate::bus_admin::BusAdminClient, crate::error::GatewayError> {\n        let bus = self.event_bus.clone().ok_or_else(|| {\n            crate::error::GatewayError::Internal(anyhow::anyhow!(\n                \"gateway is not wired to a live event bus; admin operations unavailable\"\n            ))\n        })?;\n        let session_id = self.session_id.as_ref().ok_or_else(|| {\n            crate::error::GatewayError::Internal(anyhow::anyhow!(\n                \"gateway is not wired to a live kernel session; admin operations unavailable\"\n            ))\n        })?;\n        Ok(crate::bus_admin::BusAdminClient::new(\n            bus,\n            caller,\n            session_id.0,\n        ))\n    }\n\n    /// Build a bus-direct admin client for an authenticated caller, carrying\n    /// the caller's device scope through to the kernel cap-gate.\n    ///\n    /// Use this for every admin op behind the auth middleware: it stamps the\n    /// caller's `device_key_id` (when the bearer was device-scoped) onto each\n    /// outbound request so a paired device's scope is enforced kernel-side.\n    /// The two unauthenticated redeem routes (which act as the bootstrap\n    /// `default` principal) keep [`admin_client`](Self::admin_client) — their","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-gateway/src/state.rs#L406-L442","documentation":"An admin bus operation was requested while the gateway has an event bus but no kernel session id. BusAdminClient requires the session id to address the live kernel session, so admin_client() returns GatewayError::Internal when session_id is None.","triggerScenarios":"Calling admin_client() / admin_client_for() / assert_live_audit_revocation() on a state where event_bus is Some but session_id is None — e.g. the bus was wired before the gateway completed its kernel session handshake, or the handshake failed silently.","commonSituations":"Admin requests arriving during startup before session establishment; the kernel session registration step failed or was skipped in a custom embedding of the gateway; test setups that set a bus but never a session id.","solutions":["Ensure the kernel session handshake completes and stores the session id before serving admin routes","Check startup logs for session registration failures and fix the underlying connect error","Delay/readiness-gate admin endpoints until state.session_id is Some","Fix the construction site to pass the session id alongside the event bus"],"exampleFix":"// before\nlet state = GatewayState::new(config, event_bus, None)?;\n// after\nlet session = connect_kernel_session(&event_bus).await?;\nlet state = GatewayState::new(config, event_bus, Some(session.id()))?;","handlingStrategy":"validation","validationCode":"fn admin_session_ready(state: &GatewayState) -> bool {\n    state.event_bus.is_some() && state.session_id.is_some()\n}","typeGuard":"fn live_session(state: &GatewayState) -> Option<SessionId> {\n    state.session_id.as_ref().map(|s| s.0)\n}","tryCatchPattern":"if state.session_id.is_none() {\n    return Err(StatusCode::SERVICE_UNAVAILABLE); // session not established yet\n}\nlet client = state.admin_client(caller)?;","preventionTips":["Only expose admin routes after the kernel session handshake stores session_id","Fail fast at startup if session registration does not succeed","Poll state.session_id in readiness checks before accepting admin traffic"],"tags":["configuration","session","admin"],"backgroundTag":"missing-configuration","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}