vectordotdev/vector · warning · TungsteniteError

{}

Error message

{}

What it means

When the WebSocket server closes the connection, handle_close_frame inspects the close frame. If a close frame with a code exists it uses that message; if none exists, the message 'Connection closed by server without a close frame' is used and the specific error is WebSocketSourceError::RemoteClosedEmpty. Both are wrapped in an io::Error(ErrorKind::ConnectionAborted) for the emitted WebSocketReceiveError, and the specific error is returned so the source reconnects.

Solutions

  1. Treat it as an expected reconnect: Vector restarts the source automatically; check subsequent reconnection success.
  2. Investigate upstream server/proxy logs for abrupt TCP resets (LB idle timeouts, service restarts).
  3. Enable ping/pong keep-alive (ping_timeout / ping interval) to detect and recover from dead connections faster.
  4. If the server sends close frames without codes, this message is informational — handle RemoteClosedEmpty in retry logic.
Defensive patterns

Strategy: retry

Try / catch

match err {
    WebSocketSourceError::RemoteClosedEmpty => info!("server closed without close frame; reconnecting"),
    other => error!("websocket source failed: {other:?}"),
}

Prevention

When it happens

Trigger: handle_message or send_initial_message encounters a WebSocket message::Close; handle_close_frame finds no close-frame payload (code/reason absent), yielding 'Connection closed by server without a close frame' and WebSocketSourceError::RemoteClosedEmpty returned as Err.

Common situations: Server (or an intermediary) tears down the TCP connection abruptly without the WebSocket close handshake; upstream service restarts; load balancer idle timeout kills the socket; server implements close without a status code.

Related errors


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

Appendix: source

Thrown at src/sources/websocket/source.rs:374

    ) -> Result<(), WebSocketSourceError> {
        let (error_message, specific_error) = match frame {
            Some(frame) => {
                let msg = format!(
                    "Connection closed by server with code '{}' and reason: '{}'",
                    frame.code, frame.reason
                );
                let err = WebSocketSourceError::RemoteClosed {
                    frame: frame.into_owned(),
                };
                (msg, err)
            }
            None => (
                "Connection closed by server without a close frame".to_string(),
                WebSocketSourceError::RemoteClosedEmpty,
            ),
        };

        let error = TungsteniteError::Io(std::io::Error::new(
            std::io::ErrorKind::ConnectionAborted,
            error_message,
        ));
        emit!(WebSocketReceiveError { error: &error });

        Err(specific_error)
    }

    fn is_custom_pong(&self, msg_txt: &str) -> bool {
        match self.config.pong_message.as_ref() {
            Some(config) => config.matches(msg_txt),
            None => false,
        }
    }
}

struct PingManager {
    interval: PingInterval,

View on GitHub (pinned to bdb87aeaa4)