vectordotdev/vector · error

Pong not received in time

Error message

Pong not received in time

What it means

Runtime error from the WebSocket sink's connection supervision in src/sinks/websocket/sink.rs. The sink sends pings and records the last pong time; `check_received_pong_time` compares `last_pong.elapsed()` against the configured `ping_timeout` and, when exceeded, returns a tungstenite `Error::Io` with kind `TimedOut` ("Pong not received in time"). This tears down the connection and triggers the sink's reconnect-with-backoff loop.

Source

Thrown at src/sinks/websocket/sink.rs:68

            ping_timeout: config.common.ping_timeout,
        })
    }

    async fn create_sink_and_stream(
        &self,
    ) -> (
        impl Sink<Message, Error = TungsteniteError> + use<>,
        impl Stream<Item = Result<Message, TungsteniteError>> + use<>,
    ) {
        let ws_stream = self.connector.connect_backoff().await;
        ws_stream.split()
    }

    fn check_received_pong_time(&self, last_pong: Instant) -> Result<(), TungsteniteError> {
        if let Some(ping_timeout) = self.ping_timeout
            && last_pong.elapsed() > Duration::from_secs(ping_timeout.into())
        {
            return Err(TungsteniteError::Io(io::Error::new(
                io::ErrorKind::TimedOut,
                "Pong not received in time",
            )));
        }

        Ok(())
    }

    async fn handle_events<I, WS, O>(
        &mut self,
        input: &mut I,
        ws_stream: &mut WS,
        ws_sink: &mut O,
    ) -> Result<(), ()>
    where
        I: Stream<Item = Event> + Unpin,
        WS: Stream<Item = Result<Message, TungsteniteError>> + Unpin,
        O: Sink<Message, Error = TungsteniteError> + Unpin,

View on GitHub (pinned to 3708c39b12)

Solutions

  1. Increase `ping_timeout` on the WebSocket sink so legitimate latency can't trip it
  2. Confirm the server answers RFC 6455 pings (most frameworks do automatically; custom servers may not)
  3. Check proxies/LBs between Vector and the server for idle-timeout kills or filtered ping/pong frames
  4. Rely on the built-in reconnect: after this error the sink re-establishes the connection with backoff, so a one-off blip self-heals

Example fix

# before
[sinks.out]
type = "websocket"
uri = "wss://example.com/ws"
ping_timeout = 5 # too tight, trips on normal latency

# after
[sinks.out]
type = "websocket"
uri = "wss://example.com/ws"
ping_timeout = 30
Defensive patterns

Strategy: retry

Validate before calling

# Smoke-test that the endpoint answers pings before shipping
# (any RFC 6455 client with ping/pong enabled; a stalled pong = server-side problem)

Try / catch

loop {
    match run_sink_session(&mut input).await {
        Err(TungsteniteError::Io(ref e)) if e.kind() == std::io::ErrorKind::TimedOut => {
            // pong timeout: reconnect with backoff (the sink's built-in behavior)
            backoff.wait().await;
        }
        Err(e) => return Err(e),
        Ok(()) => break,
    }
}

Prevention

When it happens

Trigger: The remote WebSocket endpoint stops answering protocol-level pings (RFC 6455 pong frames) for longer than `ping_timeout` seconds: dead/unresponsive server, half-open TCP connection, silent network drop, or a proxy stripping ping/pong frames.

Common situations: WebSocket servers that don't implement pong replies; intermediaries (nginx, cloud LBs) with idle timeouts closing the connection quietly; mobile/flaky networks where the connection dies without a FIN; `ping_timeout` set lower than real round-trip times.

Related errors


AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20). Data as JSON: /api/errors/c0f80142ebc9ae16. Report an issue: GitHub.