quickwit-oss/quickwit · error

request should be set

Error message

request should be set

What it means

This `.expect("request should be set")` panic fires in `EventListener::poll` (quickwit-common/src/tower/event_listener.rs). The tower `Service` contract requires `poll_ready` to be called (and return Ready) before each `call`; `call` stores the request so that after the inner future resolves successfully, an event can be published for it. The panic means the future was polled after the request was already taken, or `call` was never invoked properly through the service stack — a violation of the tower protocol by the caller or a middleware above.

Source

Thrown at quickwit/quickwit-common/src/tower/event_listener.rs:103

    inner: F,
    event_broker: EventBroker,
    request: Option<R>,
}

impl<R, F, T, E> Future for ResponseFuture<F, R>
where
    R: Event,
    F: Future<Output = Result<T, E>>,
{
    type Output = Result<T, E>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let this = self.project();
        let response = ready!(this.inner.poll(cx));

        if response.is_ok() {
            this.event_broker
                .publish(this.request.take().expect("request should be set"));
        }
        Poll::Ready(Ok(response?))
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::time::Duration;

    use async_trait::async_trait;

    use super::*;
    use crate::pubsub::EventSubscriber;

    #[derive(Debug, Clone, Copy)]
    struct MyEvent {

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Ensure every request goes through the tower protocol: call `poll_ready` (or `.ready().await`) and wait for `Poll::Ready(Ok(()))` before each `call`.
  2. Use `tower::ServiceExt::oneshot(service, request)` or `service.ready().await?.call(req)` instead of calling `call` directly.
  3. Do not poll the returned future after it has resolved; drop it after completion.
  4. If a custom layer wraps this service, verify it does not clone or double-poll inner futures and forwards `poll_ready` correctly.

Example fix

// before: calling without readiness
let fut = service.call(request);
let res = fut.await;

// after: follow the tower protocol
use tower::ServiceExt;
let response = service.ready().await?.call(request).await?;
Defensive patterns

Strategy: type-guard

Validate before calling

// Always route requests through readiness-aware helpers
use tower::ServiceExt;
// let response = event_listener_service.ready().await?.call(req).await?;

Type guard

// Only issue a call when the service is ready
fn is_ready<S: tower::Service<R>, R>(svc: &mut S, cx: &mut std::task::Context<'_>) -> bool {
    use tower::Service;
    matches!(svc.poll_ready(cx), std::task::Poll::Ready(Ok(())))
}

Try / catch

// Panics here indicate a protocol bug; catch at the server boundary in tests
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    // drive the service via oneshot
    tower::ServiceExt::oneshot(&mut svc, req)
}));

Prevention

When it happens

Trigger: Polling the response future returned by `EventListener::call` more times than allowed after completion, calling `call` without a prior successful `poll_ready` such that the request slot handling is desynchronized, or a custom wrapper that clones/caches the future and polls it twice.

Common situations: Hand-written tower middleware or load-balancing layers that violate the poll_ready/call contract; code that collects service futures and re-polls them; custom service implementations built on quickwit's event listener layer that bypass `ServiceExt::ready()`.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/13dcae15a48a2864. Report an issue: GitHub.