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

gateway is not wired to a live event bus; agent invocation u

Error message

gateway is not wired to a live event bus; agent invocation unavailable

What it means

The POST /agent prompt SSE handler (post_prompt) requires a live event bus to dispatch the prompt and stream agent events. This error is thrown when GatewayState.event_bus is None, meaning the gateway was built without a bus. It is a defensive check: without a bus the request cannot be forwarded to the agent runtime.

Source

Thrown at crates/astrid-gateway/src/routes/agent.rs:212

#[utoipa::path(
    post,
    path = "/api/agent/prompt",
    tag = "agent",
    request_body = PromptRequest,
    responses(
        (status = 200, description = "Server-Sent Events stream of agent output. `event: ready` first, then `event: delta` chunks and/or `event: response` for the final reply. Stream closes on `response` or client disconnect.", content_type = "text/event-stream"),
        (status = 401, body = ErrorBody, description = "Missing / invalid bearer."),
        (status = 500, body = ErrorBody, description = "Gateway not wired to a live event bus."),
    )
)]
pub async fn post_prompt(
    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 Some(bus) = state.event_bus.clone() else {
        return Err(GatewayError::Internal(anyhow::anyhow!(
            "gateway is not wired to a live event bus; agent invocation unavailable"
        )));
    };

    let body: PromptRequest = crate::routes::principals::read_json_body(req).await?;
    let session_id = body
        .session_id
        .filter(|s| !s.trim().is_empty())
        .unwrap_or_else(|| Uuid::new_v4().to_string());

    // Fail fast on an unconfigured agent loop. A daemon whose loaded capsule
    // set has no prompt subscriber / response publisher (or an unsatisfied
    // required import) would otherwise emit `ready`, wait out the 5-minute
    // timeout, and close empty — the client gets no signal. So when the loop
    // is definitively NOT ready, return a single `error` SSE event and close
    // immediately.
    //
    // Readiness is read from the in-process probe the daemon wired in: it

View on GitHub (pinned to affd8760f4)

Solutions

  1. Wire a live event bus into GatewayState when constructing the gateway (pass the bus instance at build time)
  2. Enable the agent/event-bus subsystem in the gateway configuration and restart
  3. If the deployment intentionally has no agent support, stop calling the agent prompt route (return 404/route it away)
  4. Check the build/router assembly code path to ensure event_bus is set before serving

Example fix

// before: bus never provided
let state = GatewayState { store, event_bus: None };
// after
let bus = EventBus::connect(&config.bus_endpoint).await?;
let state = GatewayState { store, event_bus: Some(Arc::new(bus)) };
Defensive patterns

Strategy: validation

Validate before calling

// Rust: check before calling the prompt endpoint / building the state
pub fn ensure_agent_ready(state: &GatewayState) -> Result<(), GatewayError> {
    if state.event_bus.is_none() {
        return Err(GatewayError::Internal(anyhow::anyhow!(
            "event bus not wired; agent routes disabled"
        )));
    }
    Ok(())
}

Type guard

fn has_event_bus(state: &GatewayState) -> bool {
    matches!(state.event_bus, Some(_))
}

Try / catch

match post_prompt(state, req).await {
    Err(GatewayError::Internal(e)) if e.to_string().contains("not wired to a live event bus") => {
        StatusCode::SERVICE_UNAVAILABLE // or 503 with agent-disabled hint
    }
    other => other.map(Into::into),
}

Prevention

When it happens

Trigger: Sending a prompt request to the agent prompt route when the gateway was constructed with event_bus = None (e.g. started in a reduced/no-agent mode or a wiring bug omitted the bus).

Common situations: Deploying with a config that disables the agent/event-bus subsystem while clients still call the prompt endpoint; a startup ordering or DI bug where the bus was never injected into GatewayState; running a stripped build (e.g. tests or local mode) against agent routes.

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/346fd1db0d729704. Report an issue: GitHub.