vectordotdev/vector · critical
poll_ready must be called first
Error message
poll_ready must be called first
What it means
NetService::call panics when invoked while the internal state is not NetworkServiceState::Connected. The service swaps state to Sending on call, so like any Tower service it must have poll_ready() return Ready (restoring Connected) before call(). Hitting this means the ready/call protocol was violated. It is an internal invariant violation of the framed-network service state machine.
Solutions
- Ensure poll_ready() is awaited until Ready(Ok(())) immediately before each call()
- Do not reuse the service for a second request before re-polling poll_ready()
- Use tower::buffer::Buffer or Vector's existing service builders so the protocol is enforced for you
Example fix
// before net_service.call(buf).await; // after ready!(net_service.poll_ready(cx))?; net_service.call(buf);
Defensive patterns
Strategy: type-guard
Validate before calling
// Check readiness before sending ready!(service.poll_ready(cx))?; // must yield Ready(Ok(())) before call
Type guard
fn is_connected(state: &NetworkServiceState) -> bool { matches!(state, NetworkServiceState::Connected(_)) } Prevention
- Follow the Tower contract: poll_ready → call, one request at a time
- Never call twice without an intervening ready poll
- Compose through tower::buffer::Buffer for automatic readiness management
When it happens
Trigger: Calling the service without a prior successful poll_ready(); calling call() twice without re-polling poll_ready(); wrapping the service in middleware that ignores readiness.
Common situations: Custom sink drivers or Tower layers composed around Vector's net service during development; regressions after refactoring batch/send drivers that bypass the readiness handshake.
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
- Maximum requests in-flight; poll_ready must be called first
- ServiceSink service sender dropped.
- a record with a next ID must have an event count
- a valid HTTP/1 URI is valid as an HTTP URI
- a validated HTTP endpoint is a valid `http 1` URI
AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16).
Data as JSON: /api/errors/5c04efda4bfd018d.
Report an issue: GitHub.
Appendix: source
Thrown at src/sinks/util/service/net/mod.rs:333
Ok(maybe_socket) => match maybe_socket {
Some(socket) => NetworkServiceState::Connected(socket),
None => NetworkServiceState::Disconnected,
},
Err(_) => return Poll::Ready(Err(NetError::ServiceSocketChannelClosed)),
}
}
};
}
Poll::Ready(Ok(()))
}
fn call(&mut self, buf: Vec<u8>) -> Self::Future {
let (tx, rx) = oneshot::channel();
let mut socket = match std::mem::replace(&mut self.state, NetworkServiceState::Sending(rx))
{
NetworkServiceState::Connected(socket) => socket,
_ => panic!("poll_ready must be called first"),
};
Box::pin(async move {
match socket.send(&buf).await.context(net_error::FailedToSend) {
Ok(sent) => {
// Emit an error if we weren't able to send the entire buffer.
if sent != buf.len() {
socket.on_partial_send(buf.len(), sent);
}
// Send the socket back to the service, since theoretically it's still valid to
// reuse given that we may have simply overrun the OS socket buffers, etc.
tx.send(Some(socket)).ok();
Ok(sent)
}
Err(e) => {
// We need to signal back to the service that it needs to create a fresh socketView on GitHub (pinned to bdb87aeaa4)