{"record":{"id":"14bd8beabc1729c0","repo":"astrid-runtime/astrid","slug":"gateway-is-not-wired-to-a-live-event-bus-agent-ap","errorCode":null,"errorMessage":"gateway is not wired to a live event bus; agent approval unavailable","messagePattern":"gateway is not wired to a live event bus; agent approval unavailable","errorType":"http","errorClass":"GatewayError::Internal","httpStatus":500,"severity":"error","filePath":"crates/astrid-gateway/src/routes/agent.rs","lineNumber":512,"sourceCode":"    post,\n    path = \"/api/agent/approval-response\",\n    tag = \"agent\",\n    request_body = ApprovalResponseRequest,\n    responses(\n        (status = 202, description = \"Approval decision accepted and published onto the approval reply topic.\"),\n        (status = 400, body = ErrorBody, description = \"Malformed request id or unsupported decision.\"),\n        (status = 401, body = ErrorBody, description = \"Missing / invalid bearer.\"),\n        (status = 500, body = ErrorBody, description = \"Gateway not wired to a live event bus.\"),\n    )\n)]\npub async fn post_approval_response(\n    State(state): State<Arc<GatewayState>>,\n    req: Request<axum::body::Body>,\n) -> GatewayResult<impl IntoResponse> {\n    let caller = caller_from(&req)?.clone();\n\n    let Some(bus) = state.event_bus.clone() else {\n        return Err(GatewayError::Internal(anyhow::anyhow!(\n            \"gateway is not wired to a live event bus; agent approval unavailable\"\n        )));\n    };\n\n    let body: ApprovalResponseRequest = crate::routes::principals::read_json_body(req).await?;\n    body.validate()\n        .map_err(|m| GatewayError::BadRequest(m.to_string()))?;\n\n    publish_approval_response(&bus, caller.principal.as_str(), body);\n\n    Ok(StatusCode::ACCEPTED)\n}\n\n/// Publish an elicit answer onto the per-request reply topic the host lifecycle\n/// waiter is blocked on (`astrid.v1.elicit.response.{request_id}`), stamped with\n/// the caller's verified `principal`.\n///\n/// Split out of [`post_elicit_response`] so the message construction +","sourceCodeStart":494,"sourceCodeEnd":530,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-gateway/src/routes/agent.rs#L494-L530","documentation":"This is an Internal (500) error thrown by the agent approval endpoint when GatewayState.event_bus is None. The gateway can be built without a live event bus (e.g. in reduced/test configurations or when the bus wiring failed at startup), and approval responses require publishing an event to the bus, so the route refuses to run rather than silently dropping the approval.","triggerScenarios":"Calling POST /api/agent/approval-response (post_approval_response handler) while the gateway was constructed with event_bus: None — i.e. the server was started without a live event bus wired into GatewayState.","commonSituations":"Gateway started in a degraded/test/offline mode where the event bus is not instantiated; a startup bug or config change that skips bus construction; hitting an approval endpoint on a node whose event bus failed to initialize.","solutions":["Wire a live event bus into GatewayState at gateway startup (the code at src/lib.rs only uses the bus when Some).","If the bus failed to initialize, fix the underlying startup error and restart the gateway.","Do not route agent-approval traffic to gateway instances deployed without an event bus; gate the route on bus availability.","In tests, construct GatewayState with a real (or stub) event bus instead of event_bus: None."],"exampleFix":"// before: state built without a bus\nlet state = GatewayState { event_bus: None, .. };\n// after: build and wire the bus at startup\nlet bus = EventBus::connect(&config.bus_addr).await?;\nlet state = GatewayState { event_bus: Some(Arc::new(bus)), .. };","handlingStrategy":"try-catch","validationCode":"// caller-side check before calling the approval endpoint\nif (!gatewayHealth.features?.eventBus) throw new Error('gateway has no event bus; approvals disabled');","typeGuard":"fn has_event_bus(state: &GatewayState) -> bool {\n    state.event_bus.is_some()\n}","tryCatchPattern":"try {\n  await fetch('/api/agent/approval-response', { method: 'POST', body });\n} catch (e) {\n  if (e.status === 500 && /not wired to a live event bus/.test(e.message)) {\n    // surface 'approvals unavailable' and stop retrying\n  }\n}","preventionTips":["Deploy gateways with an event bus wired if any approval flows are expected.","Add a readiness probe that reports event_bus presence so traffic is routed away from bus-less instances.","In tests, never ship a GatewayState with event_bus: None into integration suites covering approvals."],"tags":["rust","gateway","event-bus","configuration"],"backgroundTag":"feature-not-enabled","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"}