seanmonstar/warp · error

polled after complete

Error message

polled after complete

What it means

Internal invariant panic in the `Then` filter future. After the sequenced future (`second`) resolves and `State::Done` is set with the result returned, re-polling violates the `Future` contract; the library panics as no result remains.

Solutions

  1. Use `.await`/`tokio::spawn` to drive the future once to completion.
  2. Wrap with `futures::future::Fuse` and check `is_terminated()` before polling.
  3. Return from the poll loop immediately when `Poll::Ready` is seen.
  4. Ensure a single poller owns the future.

Example fix

// before
let mut fut = filter.then(next);
let _ = fut.as_mut().poll(cx);
let _ = fut.as_mut().poll(cx); // panic: polled after complete

// after
let out = filter.then(next).await; // no manual polls
Defensive patterns

Strategy: try-catch

Validate before calling

use futures::future::FusedFuture;
fn poll_guard<F: FusedFuture + Unpin>(fut: &mut F, cx: &mut Context<'_>) -> Option<F::Output> {
    if fut.is_terminated() { return None; }
    match fut.poll_unpin(cx) { Poll::Ready(v) => Some(v), _ => None }
}

Type guard

fn not_done<F: FusedFuture>(fut: &F) -> bool { !fut.is_terminated() }

Try / catch

// structural prevention:
let out = filter.then(next).await; // no manual polls, no double poll

Prevention

When it happens

Trigger: Polling the `Then` combinator future after it already returned `Poll::Ready(Ok(ex2))` — typically from a poll loop that doesn't stop at completion or an executor that re-runs finished tasks.

Common situations: Custom executors, wrappers missing `FusedFuture`, calling `poll` both from a waker-driven loop and an outer select, retry logic that re-polls consumed futures.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of seanmonstar/warp@ff34d7213e (2026-09-09). Data as JSON: /api/errors/f4972b9c78872d31. Report an issue: GitHub.

Appendix: source

Thrown at src/filter/then.rs:91

    F: Func<T::Ok>,
    F::Output: Future + Send,
{
    type Output = Result<(<F::Output as Future>::Output,), T::Error>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            match self.as_mut().project() {
                StateProj::First(first, second) => {
                    let ex1 = ready!(first.try_poll(cx))?;
                    let fut2 = second.call(ex1);
                    self.set(State::Second(fut2));
                }
                StateProj::Second(second) => {
                    let ex2 = (ready!(second.poll(cx)),);
                    self.set(State::Done);
                    return Poll::Ready(Ok(ex2));
                }
                StateProj::Done => panic!("polled after complete"),
            }
        }
    }
}

View on GitHub (pinned to ff34d7213e)