astrid-runtime/astrid · error · GatewayError::Internal

gateway is not wired to a live event bus; audit stream unava

Error message

gateway is not wired to a live event bus; audit stream unavailable

What it means

get_events streams audit events from the event bus; if the GatewayState has no event bus handle (the standalone constructor used in route-level tests), the route returns a 502-style Internal error immediately instead of hanging. This is an honest failure so dashboards don't wait forever on a stream that can never produce events.

Source

Thrown at crates/astrid-gateway/src/routes/events.rs:97

    )
)]
pub async fn get_events(
    State(state): State<Arc<GatewayState>>,
    req: Request<axum::body::Body>,
) -> GatewayResult<Sse<impl Stream<Item = Result<Event, Infallible>>>> {
    let caller = caller_from(&req)?.clone();
    let capability_probe = req
        .extensions()
        .get::<CapabilityProbe>()
        .cloned()
        .unwrap_or_else(CapabilityProbe::deny_all);

    // Without a bus handle (the standalone GatewayState ctor used
    // by route-level tests), report an honest 502 instead of
    // hanging — a dashboard would otherwise wait forever on a
    // stream that can never produce.
    let Some(bus) = state.event_bus.clone() else {
        return Err(GatewayError::Internal(anyhow::anyhow!(
            "gateway is not wired to a live event bus; audit stream unavailable"
        )));
    };

    // The kernel-owned probe applies the caller's live device scope.
    let initial_firehose = caller_holds(
        &capability_probe,
        &caller.principal,
        caller.device_key_id.as_deref(),
        AUDIT_FIREHOSE_CAP,
    );

    // Routed subscription so the audit firehose gets the same
    // per-(topic, principal) DRR fairness the rest of the gateway
    // SSE streams now use (#813 Layer 4). The principal-firehose
    // filter at the post-receive layer is unchanged — it's a
    // capability gate, not a routing concern.
    let receiver = bus.subscribe_topic_routed(

View on GitHub (pinned to affd8760f4)

Solutions

  1. Wire a live event bus handle into GatewayState before serving requests (state.event_bus = Some(bus))
  2. If this is a route-level test, use the full state constructor that includes the bus, or assert on the 502 behavior
  3. In production, add a startup check that fails fast when the bus is missing

Example fix

// before
let Some(bus) = state.event_bus.clone() else {
    return Err(GatewayError::Internal(anyhow::anyhow!(
        "gateway is not wired to a live event bus; audit stream unavailable"
    )));
};
// after
let bus = state.event_bus.clone().ok_or_else(|| {
    tracing::error!("event bus not configured; cannot serve audit stream");
    GatewayError::Internal(anyhow::anyhow!(
        "gateway is not wired to a live event bus; audit stream unavailable"
    ))
})?;
Defensive patterns

Strategy: try-catch

Validate before calling

// Guard before opening the stream
if state.event_bus.is_none() {
    return Err(StatusCode::SERVICE_UNAVAILABLE);
}

Type guard

fn has_event_bus(state: &GatewayState) -> bool {
    state.event_bus.is_some()
}

Try / catch

match get_events(state, caller).await {
    Ok(stream) => sse_response(stream),
    Err(GatewayError::Internal(e)) if e.to_string().contains("not wired to a live event bus") => {
        // 502: bus unavailable, do not retry against this instance
        service_unavailable("audit stream unavailable")
    }
    Err(e) => internal_error(e),
}

Prevention

When it happens

Trigger: Calling the /events SSE endpoint against a GatewayState built without wiring an event bus (e.g. in tests using the standalone GatewayState constructor, or a deployment where the bus handle was never attached).

Common situations: Integration tests constructing GatewayState manually; a misconfigured deployment that skipped bus initialization; refactoring that dropped the bus from state assembly.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/717fc4c00f1b22ca. Report an issue: GitHub.