{"record":{"id":"c7b7d3a3a0085e39","repo":"vectordotdev/vector","slug":"maximum-requests-in-flight-poll-ready-must-be-cal","errorCode":null,"errorMessage":"Maximum requests in-flight; poll_ready must be called first","messagePattern":"Maximum requests in-flight; poll_ready must be called first","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/sinks/util/adaptive_concurrency/service.rs","lineNumber":77,"sourceCode":"            self.state = match self.state {\n                State::Ready(_) => return self.inner.poll_ready(cx).map_err(Into::into),\n                State::Waiting(ref mut fut) => {\n                    tokio::pin!(fut);\n                    let permit = ready!(fut.poll(cx));\n                    State::Ready(permit)\n                }\n                State::Empty => State::Waiting(Box::pin(Arc::clone(&self.controller).acquire())),\n            };\n        }\n    }\n\n    fn call(&mut self, request: Request) -> Self::Future {\n        // Make sure a permit has been acquired\n        let permit = match mem::replace(&mut self.state, State::Empty) {\n            // Take the permit.\n            State::Ready(permit) => permit,\n            // whoopsie!\n            _ => panic!(\"Maximum requests in-flight; poll_ready must be called first\"),\n        };\n\n        self.controller.start_request();\n\n        // Call the inner service\n        let future = self.inner.call(request);\n\n        ResponseFuture::new(future, permit, Arc::clone(&self.controller))\n    }\n}\n\nimpl<S, L> Load for AdaptiveConcurrencyLimit<S, L> {\n    type Metric = f64;\n\n    fn load(&self) -> Self::Metric {\n        self.controller.load()\n    }\n}","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/src/sinks/util/adaptive_concurrency/service.rs#L59-L95","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet fut = service.call(req);\n\n// after\nready!(service.poll_ready(cx))?;\nlet fut = service.call(req);","handlingStrategy":"type-guard","validationCode":"// Before calling, assert readiness\nassert!(matches!(svc.poll_ready(PollCtx), Poll::Ready(Ok(()))));","typeGuard":"fn is_ready(state: &State) -> bool { matches!(state, State::Ready(_)) }","tryCatchPattern":null,"preventionTips":["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"],"tags":["rust","tower","async","panic","concurrency"],"backgroundTag":"internal-invariant-violation","analyzedSha":"bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}