{"record":{"id":"85a2600fea44e344","repo":"vectordotdev/vector","slug":"backoff-iterator-always-returns-some-value","errorCode":null,"errorMessage":"backoff iterator always returns some value","messagePattern":"backoff iterator always returns some value","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/common/websocket.rs","lineNumber":178,"sourceCode":"                    emit!(WebSocketConnectionEstablished {});\n                    return ws_stream;\n                }\n                Ok(Err(error)) => {\n                    emit!(WebSocketConnectionFailedError {\n                        error: Box::new(error)\n                    });\n                }\n                Err(_) => {\n                    emit!(WebSocketConnectionFailedError {\n                        error: Box::new(WebSocketError::ConnectionTimedOut),\n                    });\n                }\n            }\n\n            time::sleep(\n                backoff\n                    .next()\n                    .expect(\"backoff iterator always returns some value\"),\n            )\n            .await;\n        }\n    }\n\n    #[cfg(feature = \"sinks-websocket\")]\n    pub(crate) async fn healthcheck(&self) -> crate::Result<()> {\n        self.connect().await.map(|_| ()).map_err(Into::into)\n    }\n}\n\npub(crate) const fn is_closed(error: &TungsteniteError) -> bool {\n    matches!(\n        error,\n        TungsteniteError::ConnectionClosed\n            | TungsteniteError::AlreadyClosed\n            | TungsteniteError::Protocol(ProtocolError::ResetWithoutClosingHandshake)\n    )","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/src/common/websocket.rs#L160-L196","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the backoff is constructed as an infinite iterator (e.g. `ExponentialBackoff` with `max_attempts: None`/infinite)","Fix the underlying connect failure (check endpoint URL, proxy, network) — the panic only follows repeated connection errors","Update Vector if on an older release; report if reproducible on current code"],"exampleFix":"// before\nlet backoff = Backoff::exponential(1, 5).take(3); // finite\n// after\nlet backoff = Backoff::exponential(1, 5); // infinite, never exhausts","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Guard infinite backoff usage:\nlet delay = backoff.next().unwrap_or(std::time::Duration::from_secs(30));","preventionTips":["Always use infinite backoff iterators for reconnect loops","Fix underlying network/endpoint failures instead of relying on retries","Check WebSocket endpoint reachability before starting long-lived validation"],"tags":["rust","websocket","backoff","reconnect"],"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"}