seanmonstar/warp · error
polled after complete
Error message
polled after complete
What it means
Internal invariant panic in the `AndThen` filter's combinator future. Once the chained future completes and the result is returned, the state machine moves to `State::Done`; polling after that violates the `Future` contract and there is no value to return, so the library panics.
Solutions
- Drive the filter future with `.await` or `tokio::spawn` rather than manual `poll` calls.
- Wrap the future with `futures::future::Fuse` and check `is_terminated()` before polling.
- Never poll a future again after it yields `Poll::Ready`; drop it instead.
- Review custom executors/wrappers for double-polling logic.
Example fix
// before
loop {
let _ = Pin::new(&mut fut).poll(cx); // keeps polling after Ready -> panic
}
// after
use futures::future::FusedFuture;
let mut fut = filter.and_then(svc).fuse();
while !fut.is_terminated() {
let _ = futures::poll!(fut.as_mut());
} Defensive patterns
Strategy: try-catch
Validate before calling
use futures::future::FusedFuture;
if fut.is_terminated() { return; } // skip poll after completion Type guard
fn can_poll<F: FusedFuture>(fut: &F) -> bool { !fut.is_terminated() } Try / catch
// panic is not recoverable; avoid by construction:
let mut fut = filter.and_then(svc).fuse();
if !fut.is_terminated() { let _ = fut.poll_unpin(cx); } Prevention
- Use `.await` instead of manual `poll` wherever possible.
- Implement `FusedFuture` semantics in custom wrappers.
- Guard poll sites with `is_terminated()` checks.
- Don't cache and reuse futures after they resolve.
When it happens
Trigger: Polling the `AndThen` combinator future after it has returned `Poll::Ready` (the `StateProj::Done` branch) — caused by a custom executor re-polling a completed future or a wrapper that ignores `is_terminated`.
Common situations: Hand-rolled executors, select!/timeout wrappers written incorrectly, reusing a consumed future from a cache, or combining raw futures without `Fuse`.
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/a4bd2c1556831918.
Report an issue: GitHub.
Appendix: source
Thrown at src/filter/and_then.rs:106
>;
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 = match ready!(second.try_poll(cx)) {
Ok(item) => Ok((item,)),
Err(err) => Err(From::from(err)),
};
self.set(State::Done);
return Poll::Ready(ex2);
}
StateProj::Done => panic!("polled after complete"),
}
}
}
}
View on GitHub (pinned to ff34d7213e)