vectordotdev/vector · error · std::io::Error
NotConnected
NotConnected
Error message
Can't set keepalive on connection that has not been accepted yet.
What it means
Runtime `io::Error` (kind `NotConnected`) from `MaybeTlsIncomingStream::set_keepalive` in lib/vector-core/src/tls/incoming.rs. The stream wraps a state machine: with TLS enabled the connection starts in `StreamState::Accepting` (handshake future in flight) and `get_ref()` only returns the `TcpStream` once the handshake completes and state becomes `Accepted`. Calling `set_keepalive` before that yields this error.
Source
Thrown at lib/vector-core/src/tls/incoming.rs:294
),
None => StreamState::Accepted(MaybeTlsStream::Raw(stream)),
};
Self { state, peer_addr }
}
// Explicit handshake method
pub async fn handshake(&mut self) -> crate::tls::Result<()> {
if let StreamState::Accepting(fut) = &mut self.state {
let stream = fut.await?;
self.state = StreamState::Accepted(MaybeTlsStream::Tls(stream));
}
Ok(())
}
pub fn set_keepalive(&mut self, keepalive: TcpKeepaliveConfig) -> io::Result<()> {
let stream = self.get_ref().ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotConnected,
"Can't set keepalive on connection that has not been accepted yet.",
)
})?;
if let Some(time_secs) = keepalive.time_secs {
let config =
socket2::TcpKeepalive::new().with_time(std::time::Duration::from_secs(time_secs));
tcp::set_keepalive(stream, &config)?;
}
Ok(())
}
pub fn set_receive_buffer_bytes(&mut self, bytes: usize) -> std::io::Result<()> {
let stream = self.get_ref().ok_or_else(|| {
io::Error::new(View on GitHub (pinned to 3708c39b12)
Solutions
- Await the handshake first: `stream.handshake().await?;` then `stream.set_keepalive(cfg)?`
- Or defer setting keepalive until after the first successful read/write (which also completes the handshake)
- Treat `ErrorKind::NotConnected` from this call as 'not yet accepted' — retry after the handshake rather than failing the connection
Example fix
// before let mut stream = listener.accept().await?; stream.set_keepalive(keepalive)?; // fails under TLS // after let mut stream = listener.accept().await?; stream.handshake().await?; stream.set_keepalive(keepalive)?;
Defensive patterns
Strategy: validation
Validate before calling
// Only tune socket options once the TLS handshake is done
stream.handshake().await?; // completes Accepting -> Accepted
if stream.get_ref().is_some() {
stream.set_keepalive(keepalive)?;
} Try / catch
match stream.set_keepalive(cfg) {
Err(e) if e.kind() == std::io::ErrorKind::NotConnected => {
// handshake still pending: drive I/O or await handshake(), then retry once
}
Err(e) => return Err(e.into()),
Ok(()) => {}
} Prevention
- Always await handshake() before any socket-option call on MaybeTlsIncomingStream
- Test socket-tuning code paths with TLS enabled, not just plain TCP
- get_ref().is_some() tells you whether the underlying TcpStream is reachable yet
When it happens
Trigger: In a TCP source with TLS enabled, calling `stream.set_keepalive(...)` immediately after accept, before `stream.handshake().await` has completed (or before any read/write drove the handshake to completion). With plain TCP (no acceptor) the state is `Accepted` from construction, so the same code appears to work until TLS is configured.
Common situations: Sources that configure `keepalive_time_secs` per connection (e.g. socket sources adding keepalive in their connection setup) and only fail in TLS deployments; also hitting the `Closed` state after the connection was torn down.
Related errors
- systemd fd already consumed
- path and query should never fail to parse
- Serializer does not support JSON
- Paths must always start with a leading forward slash (`/`).
- Only leaf nodes should be allowed to be non-object values.
AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20).
Data as JSON: /api/errors/3344fdcfcaa53fc1.
Report an issue: GitHub.