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
- Use `.await`/`tokio::spawn` to drive the future once to completion.
- Wrap with `futures::future::Fuse` and check `is_terminated()` before polling.
- Return from the poll loop immediately when `Poll::Ready` is seen.
- 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
- Drive futures only via async/await or tokio::spawn.
- Use Fuse and check `is_terminated()` for manual polling.
- Ensure retry logic recreates futures rather than re-polling them.
- Keep a single poller per future.
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
- polled after complete
- polled after complete
- polled after complete
- polled after complete
- polled after complete
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)