astrid-runtime/astrid · error · anyhow::Error

event bus closed before response on {want_response}

Error message

event bus closed before response on {want_response}

What it means

BusAdminClient::request subscribes to the response topic before publishing the request. If receiver.recv() returns Ok(None), the broadcast channel's sender side has been dropped — the event bus shut down — so no response can ever arrive. This error reports that the bus closed while the request was still in flight for the given response topic.

Source

Thrown at crates/astrid-gateway/src/bus_admin.rs:157

            message: msg,
        });

        let deadline = tokio::time::Instant::now()
            .checked_add(self.timeout)
            .unwrap_or_else(tokio::time::Instant::now);

        loop {
            let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());
            if remaining.is_zero() {
                return Err(anyhow!(
                    "bus admin request timed out after {:?} waiting for {want_response}",
                    self.timeout
                ));
            }
            let event = match tokio::time::timeout(remaining, receiver.recv()).await {
                Ok(Some(ev)) => ev,
                Ok(None) => {
                    return Err(anyhow!(
                        "event bus closed before response on {want_response}"
                    ));
                },
                Err(_) => {
                    return Err(anyhow!(
                        "bus admin request timed out after {:?} waiting for {want_response}",
                        self.timeout
                    ));
                },
            };

            let AstridEvent::Ipc { message, .. } = &*event else {
                continue;
            };
            if message.source_id != self.expected_source_id {
                continue;
            }
            // The kernel's `publish_response` wraps the

View on GitHub (pinned to affd8760f4)

Solutions

  1. Ensure the event bus outlives all in-flight admin requests (hold the sender until requests complete)
  2. Check for premature shutdown/teardown ordering in the gateway startup/shutdown code
  3. Retry the request after the bus is re-established, or surface a clean 'shutting down' state to the caller
  4. In tests, await requests before dropping the bus fixture

Example fix

// before
drop(bus); // sender dropped while request in flight
let resp = client.request(kind).await?;
// after
let resp = client.request(kind).await?; // keep bus alive until response
drop(bus);
Defensive patterns

Strategy: try-catch

Validate before calling

// Check the bus is alive before issuing:
if bus_sender_count() == 0 { return Err(anyhow!("event bus unavailable")); }

Try / catch

match client.request(kind).await {
    Ok(resp) => resp,
    Err(e) if e.to_string().contains("event bus closed") => {
        // treat as shutdown: stop issuing requests, surface clean shutdown state
        Err(anyhow!("gateway is shutting down"))
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling request() while the event bus / its publisher is being shut down; the bus handle holding the sender is dropped mid-request (e.g. process teardown, a test dropping the bus); recv on a broadcast Receiver whose Sender has gone away.

Common situations: Graceful shutdown racing an in-flight admin request; unit/integration tests dropping the bus fixture before awaiting the response; kernel process exit closing the shared bus.

Related errors


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