herdrdev/herdr · error · ClientError::Protocol
expected Welcome message
Error message
expected Welcome message
What it means
During the client handshake, the first server message must be protocol::ServerMessage::Welcome; any other decoded message yields ClientError::Protocol with io::ErrorKind::InvalidData 'expected Welcome message' (src/client/mod.rs:893). It indicates the stream is alive but is speaking a different protocol or is out of sync — a version/wire mismatch rather than a dead connection.
Source
Thrown at src/client/mod.rs:893
stream,
None,
"failed to clear client handshake read timeout",
)?;
match welcome {
ServerMessage::Welcome {
version,
encoding,
error,
} => {
if let Some(error) = error {
return Err(ClientError::HandshakeRejected { version, error });
}
info!(version, ?encoding, "handshake succeeded");
Ok(encoding)
}
_ => Err(ClientError::Protocol(protocol::FramingError::Io(
io::Error::new(io::ErrorKind::InvalidData, "expected Welcome message"),
))),
}
}
// ---------------------------------------------------------------------------
// Client event loop
// ---------------------------------------------------------------------------
/// Internal events for the client event loop.
enum ClientLoopEvent {
/// Raw input bytes from stdin.
#[cfg(unix)]
StdinInput(Vec<u8>),
/// One confirmed SGR pixel report with geometry captured by the reader.
#[cfg(unix)]
PixelMouse(Vec<u8>, crate::input::mouse::HostGeometry),
#[cfg(unix)]
DirectGraphicsResponse(direct_graphics::Response),View on GitHub (pinned to f457cff4f2)
Solutions
- Make client and server come from the same herdr build/version (herdr update on both, or restart the server with the same binary)
- Verify HERDR_SOCKET_PATH/HERDR_CLIENT_SOCKET_PATH point at the herdr-dev or matching server socket, not another service
- When developing inside Herdr, use: env -u HERDR_SOCKET_PATH -u HERDR_CLIENT_SOCKET_PATH cargo run -- <cmd>
- If you maintain a fork and changed the wire format, bump PROTOCOL_VERSION in src/protocol/wire.rs
Example fix
# before (debug client talking to stable server socket) cargo run -- status # after env -u HERDR_SOCKET_PATH -u HERDR_CLIENT_SOCKET_PATH cargo run -- status
Defensive patterns
Strategy: try-catch
Try / catch
match do_handshake(...) {
Err(ClientError::Protocol(protocol::FramingError::Io(e)))
if e.kind() == io::ErrorKind::InvalidData =>
Err("client/server protocol mismatch: use matching herdr versions".into()),
r => r,
} Prevention
- Run client and server from the same herdr install
- Bump PROTOCOL_VERSION whenever the wire format changes
- When testing debug builds, unset inherited socket overrides
When it happens
Trigger: do_handshake (used by connect_terminal_session_stream and run_client_with_mode) receives a non-Welcome first frame. Happens when a client of one protocol version connects to a server of an incompatible version, or when the socket actually serves a different protocol (wrong socket path).
Common situations: Mixing a stable herdr binary with a preview/dev server (or vice versa) sharing one socket, protocol changes without PROTOCOL_VERSION bump, or pointing HERDR_SOCKET_PATH at a non-herdr Unix socket.
Related errors
- stream frame header is too large
- server closed connection
- api request line is too large
- timed out reading api request
- timed out waiting for app response after {} ms
AI-assisted analysis of herdrdev/herdr@f457cff4f2 (2026-08-28).
Data as JSON: /api/errors/f7a42a20b417c631.
Report an issue: GitHub.