vectordotdev/vector · error

linger should exists for poll_flush

Error message

linger should exists for poll_flush

What it means

This panic fires in the partition batch sink's `poll_flush` when `lingers.get_mut(partition)` returns `None` for a partition that has an active batch. The sink maintains `partitions` and `lingers` maps in lockstep (every batched partition gets a linger timer), so a missing linger is an internal state inconsistency.

Solutions

  1. Report as a bug to Vector with the sink type and scenario.
  2. Check for recent patches to the partition batch sink that alter partitions/lingers bookkeeping.
  3. Restart the topology to clear inconsistent in-memory state and confirm reproducibility.
Defensive patterns

Strategy: fallback

Prevention

When it happens

Trigger: Polling flush on a partitioned sink where the `partitions` map contains a key absent from `lingers` — e.g. a logic bug that inserts a batch without a corresponding linger, or removes a linger without removing the batch.

Common situations: Not reachable via configuration; appears only from bugs in partition lifecycle code or custom patches to src/sinks/util/sink.rs.

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


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/3ff25f364ca93a27. Report an issue: GitHub.

Appendix: source

Thrown at src/sinks/util/sink.rs:298

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        loop {
            // Poll inner service while not ready, if we don't have buffer or any batch.
            if self.buffer.is_none() && self.partitions.is_empty() {
                ready!(self.service.poll_complete(cx));
                return Poll::Ready(Ok(()));
            }

            // Try send batches.
            let this = self.as_mut().project();
            let mut partitions_ready = vec![];
            for (partition, batch) in this.partitions.iter() {
                if ((*this.closing && !batch.is_empty())
                    || batch.was_full()
                    || matches!(
                        this.lingers
                            .get_mut(partition)
                            .expect("linger should exists for poll_flush")
                            .poll_unpin(cx),
                        Poll::Ready(())
                    ))
                    && this
                        .in_flight
                        .as_mut()
                        .and_then(|map| map.get_mut(partition))
                        .map(|req| matches!(req.poll_unpin(cx), Poll::Ready(())))
                        .unwrap_or(true)
                {
                    partitions_ready.push(partition.clone());
                }
            }
            let mut batch_consumed = false;
            for partition in partitions_ready.iter() {
                let service_ready = match this.service.poll_ready(cx) {
                    Poll::Ready(Ok(())) => true,
                    Poll::Ready(Err(error)) => return Poll::Ready(Err(error)),

View on GitHub (pinned to bdb87aeaa4)