vectordotdev/vector · critical
Maximum requests in-flight; poll_ready must be called first
Error message
Maximum requests in-flight; poll_ready must be called first
What it means
This panic fires in AdaptiveConcurrencyService::call when call() is invoked without a previously acquired concurrency permit. The Tower Service contract requires poll_ready() to return Poll::Ready(Ok(())) before call(); the state machine stores the permit in State::Ready, and call() consumed a state that was not Ready. This is an internal invariant violation of the Tower service protocol, not a user-facing condition.
Solutions
- Ensure every call() is preceded by poll_ready() returning Ready(Ok(())) per the Tower contract
- Re-poll poll_ready() after each call() since the service returns to NotReady while a request is in flight
- Route the service through tower::buffer::Buffer, which handles the ready/call protocol automatically
Example fix
// before let fut = service.call(req); // after ready!(service.poll_ready(cx))?; let fut = service.call(req);
Defensive patterns
Strategy: type-guard
Validate before calling
// Before calling, assert readiness assert!(matches!(svc.poll_ready(PollCtx), Poll::Ready(Ok(()))));
Type guard
fn is_ready(state: &State) -> bool { matches!(state, State::Ready(_)) } Prevention
- Always call poll_ready() until Ready before every call()
- Re-poll after each request; the service is not ready while one is in flight
- Wrap with tower::buffer::Buffer to let the buffer enforce the protocol
When it happens
Trigger: Calling the service without a preceding poll_ready()==Ready; calling call() twice without re-polling poll_ready() after the first request; a custom Tower layer or buffer that bypasses poll_ready.
Common situations: Custom sink code or third-party Tower middleware wrapping Vector's adaptive-concurrency service incorrectly; regressing during sink refactors where the ready/call handshake is broken.
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
- poll_ready must be called first
- Failed to get entry for dir
- join error or bad poll
- mutex poisoned
- producer unexpectedly dropped
AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16).
Data as JSON: /api/errors/c7b7d3a3a0085e39.
Report an issue: GitHub.
Appendix: source
Thrown at src/sinks/util/adaptive_concurrency/service.rs:77
self.state = match self.state {
State::Ready(_) => return self.inner.poll_ready(cx).map_err(Into::into),
State::Waiting(ref mut fut) => {
tokio::pin!(fut);
let permit = ready!(fut.poll(cx));
State::Ready(permit)
}
State::Empty => State::Waiting(Box::pin(Arc::clone(&self.controller).acquire())),
};
}
}
fn call(&mut self, request: Request) -> Self::Future {
// Make sure a permit has been acquired
let permit = match mem::replace(&mut self.state, State::Empty) {
// Take the permit.
State::Ready(permit) => permit,
// whoopsie!
_ => panic!("Maximum requests in-flight; poll_ready must be called first"),
};
self.controller.start_request();
// Call the inner service
let future = self.inner.call(request);
ResponseFuture::new(future, permit, Arc::clone(&self.controller))
}
}
impl<S, L> Load for AdaptiveConcurrencyLimit<S, L> {
type Metric = f64;
fn load(&self) -> Self::Metric {
self.controller.load()
}
}View on GitHub (pinned to bdb87aeaa4)