{"record":{"id":"405cb1aeef668f5d","repo":"BloopAI/vibe-kanban","slug":"unsupported-relay-ws-envelope-version","errorCode":null,"errorMessage":"unsupported relay WS envelope version","messagePattern":"unsupported relay WS envelope version","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/relay-ws/src/crypto.rs","lineNumber":90,"sourceCode":"    pub(crate) fn new(request_signature: &RequestSignature, peer_verify_key: VerifyingKey) -> Self {\n        Self {\n            request_signature: request_signature.clone(),\n            inbound_seq: 0,\n            peer_verify_key,\n        }\n    }\n\n    /// Verify a signed JSON envelope and deserialize it back into a frame.\n    ///\n    /// Checks the Ed25519 signature and enforces monotonic sequence ordering.\n    pub(crate) fn decode(&mut self, raw: &[u8]) -> anyhow::Result<RelayWsFrame> {\n        use anyhow::Context as _;\n\n        let envelope: SignedWsEnvelope =\n            serde_json::from_slice(raw).context(\"invalid relay WS envelope JSON\")?;\n\n        if envelope.version != ENVELOPE_VERSION {\n            anyhow::bail!(\"unsupported relay WS envelope version\");\n        }\n\n        let expected_seq = self.inbound_seq.saturating_add(1);\n        if envelope.seq != expected_seq {\n            anyhow::bail!(\n                \"invalid relay WS sequence: expected {expected_seq}, got {}\",\n                envelope.seq\n            );\n        }\n\n        let payload = BASE64_STANDARD\n            .decode(&envelope.payload_b64)\n            .context(\"invalid relay WS payload\")?;\n\n        let signing_input = ws_signing_input(\n            &self.request_signature,\n            envelope.seq,\n            envelope.msg_type,","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/crates/relay-ws/src/crypto.rs#L72-L108","documentation":"Relay WS messages are carried in signed envelopes with a version field; decode() rejects envelopes whose version differs from the compiled-in ENVELOPE_VERSION to prevent cross-version protocol confusion and downgrade attacks. A mismatch means the peer speaks a different envelope format.","triggerScenarios":"decode() receives an envelope JSON with a version number not equal to ENVELOPE_VERSION — e.g. produced by an older or newer relay node, or corrupted envelope JSON that happens to parse.","commonSituations":"Mixed-version cluster after a protocol bump; host/relay deployed from different builds; manually crafted or replayed envelope data.","solutions":["Deploy matching versions of relay-ws on both peers (upgrade the outdated one)","Confirm ENVELOPE_VERSION on both sides after pulls/releases","Pin protocol version in deployment configuration"],"exampleFix":"// before\nlet envelope = SignedWsEnvelope { version: 1, .. }; // peer expects version 2\n// after\nlet envelope = SignedWsEnvelope { version: ENVELOPE_VERSION, .. }; // rebuild/redeploy both sides","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn has_supported_version(env: &SignedWsEnvelope) -> bool { env.version == ENVELOPE_VERSION }","tryCatchPattern":"match crypto.decode(raw) { Err(e) if e.to_string().contains(\"unsupported relay WS envelope version\") => negotiate_version_and_reconnect(), other => other? }","preventionTips":["Deploy all relay nodes in lockstep on protocol changes","Include ENVELOPE_VERSION in handshake/health endpoints","Alert on version mismatch errors to catch skewed deployments early"],"tags":["protocol","versioning","websocket","crypto"],"backgroundTag":"envelope-version-mismatch","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}