{"record":{"id":"f9908a928fc7e223","repo":"rathole-org/rathole","slug":"protocol-version-mismatched-expected-got","errorCode":null,"errorMessage":"Protocol version mismatched. Expected {}, got {}. Please update `rathole`.","messagePattern":"Protocol version mismatched\\. Expected (.+?), got (.+?)\\. Please update `rathole`\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/protocol.rs","lineNumber":188,"sourceCode":"        }\n    }\n}\n\nlazy_static! {\n    static ref PACKET_LEN: PacketLength = PacketLength::new();\n}\n\npub async fn read_hello<T: AsyncRead + AsyncWrite + Unpin>(conn: &mut T) -> Result<Hello> {\n    let mut buf = vec![0u8; PACKET_LEN.hello];\n    conn.read_exact(&mut buf)\n        .await\n        .with_context(|| \"Failed to read hello\")?;\n    let hello = bincode::deserialize(&buf).with_context(|| \"Failed to deserialize hello\")?;\n\n    match hello {\n        Hello::ControlChannelHello(v, _) => {\n            if v != CURRENT_PROTO_VERSION {\n                bail!(\n                    \"Protocol version mismatched. Expected {}, got {}. Please update `rathole`.\",\n                    CURRENT_PROTO_VERSION,\n                    v\n                );\n            }\n        }\n        Hello::DataChannelHello(v, _) => {\n            if v != CURRENT_PROTO_VERSION {\n                bail!(\n                    \"Protocol version mismatched. Expected {}, got {}. Please update `rathole`.\",\n                    CURRENT_PROTO_VERSION,\n                    v\n                );\n            }\n        }\n    }\n\n    Ok(hello)","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/rathole-org/rathole/blob/a292f7ed5402f840415fc6a53827da2f34337856/src/protocol.rs#L170-L206","documentation":"read_hello deserializes the peer's hello message and checks the embedded protocol version against CURRENT_PROTO_VERSION. When a ControlChannelHello carries a different version, it bails because control-channel peers must speak the same protocol. This guards against incompatible client/server builds.","triggerScenarios":"Connecting a rathole client to a server built from a different (older or newer) version; the ControlChannelHello variant's version field differs from CURRENT_PROTO_VERSION in read_hello.","commonSituations":"Upgrading the server binary but not the client (or vice versa); a distro package pinned to an old rathole release talking to a recent server; cached old binaries in Docker images.","solutions":["Upgrade the older side: rebuild/update rathole on both client and server to the same version","Pin matching versions (same release) on both ends of the tunnel","Check rathole --version on both ends and align before restarting","If upgrading is impossible, use compatible release channels on both sides"],"exampleFix":"// before\n$ client: rathole v0.4.8  ↔  server: rathole v0.5.0  → version mismatch\n\n// after\n$ cargo install rathole  # same latest version on both hosts\n$ client: rathole v0.5.0  ↔  server: rathole v0.5.0","handlingStrategy":"retry","validationCode":"// Check version parity before connecting:\n$ rathole --version\n$ ssh server 'rathole --version'\n// Both must print the same version.","typeGuard":null,"tryCatchPattern":"// Retry with backoff only after fixing versions; a version mismatch never heals on retry:\nmatch client_connect().await {\n    Err(e) if e.to_string().contains(\"Protocol version mismatched\") => {\n        eprintln!(\"Upgrade both rathole ends to the same version, then restart\");\n        std::process::exit(1);\n    }\n    Err(e) => { /* transient error: retry with backoff */ }\n    Ok(v) => v,\n}","preventionTips":["Upgrade client and server together in one maintenance window","Pin the same rathole version in all Dockerfiles and package installs","Run rathole --version on both ends as a deploy checklist step"],"tags":["rust","network","protocol-version","compatibility"],"backgroundTag":"incompatible-source-type","analyzedSha":"a292f7ed5402f840415fc6a53827da2f34337856","analyzedAt":"2026-09-07T09:56:55.739Z","contentChangedAt":"2026-09-07T09:56:55.739Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}