vectordotdev/vector · error

backoff iterator always returns some value

Error message

backoff iterator always returns some value

What it means

In the WebSocket retry loop, `backoff.next()` is expected to always yield a value because the backoff iterator (an exponential backoff with `Backoff::Never` semantics / infinite iterator) is infinite. If it ever returns None the process panics, indicating the backoff object was misconfigured or exhausted unexpectedly.

Solutions

  1. Verify the backoff is constructed as an infinite iterator (e.g. `ExponentialBackoff` with `max_attempts: None`/infinite)
  2. Fix the underlying connect failure (check endpoint URL, proxy, network) — the panic only follows repeated connection errors
  3. Update Vector if on an older release; report if reproducible on current code

Example fix

// before
let backoff = Backoff::exponential(1, 5).take(3); // finite
// after
let backoff = Backoff::exponential(1, 5); // infinite, never exhausts
Defensive patterns

Strategy: fallback

Try / catch

// Guard infinite backoff usage:
let delay = backoff.next().unwrap_or(std::time::Duration::from_secs(30));

Prevention

When it happens

Trigger: A WebSocket connect loop that keeps failing: after each failed attempt the code calls `backoff.next()` to get the next delay. The panic fires only if the backoff iterator is finite/exhausted — typically from constructing it with a finite iterator or a max-attempts backoff.

Common situations: Persistent inability to reach the WebSocket endpoint combined with a code/config regression that made the backoff finite; custom builds that changed the backoff construction.

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/85a2600fea44e344. Report an issue: GitHub.

Appendix: source

Thrown at src/common/websocket.rs:178

                    emit!(WebSocketConnectionEstablished {});
                    return ws_stream;
                }
                Ok(Err(error)) => {
                    emit!(WebSocketConnectionFailedError {
                        error: Box::new(error)
                    });
                }
                Err(_) => {
                    emit!(WebSocketConnectionFailedError {
                        error: Box::new(WebSocketError::ConnectionTimedOut),
                    });
                }
            }

            time::sleep(
                backoff
                    .next()
                    .expect("backoff iterator always returns some value"),
            )
            .await;
        }
    }

    #[cfg(feature = "sinks-websocket")]
    pub(crate) async fn healthcheck(&self) -> crate::Result<()> {
        self.connect().await.map(|_| ()).map_err(Into::into)
    }
}

pub(crate) const fn is_closed(error: &TungsteniteError) -> bool {
    matches!(
        error,
        TungsteniteError::ConnectionClosed
            | TungsteniteError::AlreadyClosed
            | TungsteniteError::Protocol(ProtocolError::ResetWithoutClosingHandshake)
    )

View on GitHub (pinned to bdb87aeaa4)