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

  1. Make client and server come from the same herdr build/version (herdr update on both, or restart the server with the same binary)
  2. Verify HERDR_SOCKET_PATH/HERDR_CLIENT_SOCKET_PATH point at the herdr-dev or matching server socket, not another service
  3. When developing inside Herdr, use: env -u HERDR_SOCKET_PATH -u HERDR_CLIENT_SOCKET_PATH cargo run -- <cmd>
  4. 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

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


AI-assisted analysis of herdrdev/herdr@f457cff4f2 (2026-08-28). Data as JSON: /api/errors/f7a42a20b417c631. Report an issue: GitHub.