{"record":{"id":"c65c5c68fe684598","repo":"BloopAI/vibe-kanban","slug":"relay-yamux-session-error-e","errorCode":null,"errorMessage":"Relay yamux session error: {e}","messagePattern":"Relay yamux session error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/relay-tunnel-core/src/client.rs","lineNumber":66,"sourceCode":"    let ws_io = tungstenite_ws_stream_io(ws_stream);\n    let mut session = Session::new_client(ws_io, yamux_config());\n    let mut control = session.control();\n\n    tracing::debug!(\"Relay control channel connected\");\n\n    let shutdown = config.shutdown;\n    let local_addr = config.local_addr;\n\n    loop {\n        tokio::select! {\n            _ = shutdown.cancelled() => {\n                control.close().await;\n                return Ok(());\n            }\n            inbound = session.next() => {\n                let stream = inbound\n                    .ok_or_else(|| anyhow::anyhow!(\"Relay control channel closed\"))?\n                    .map_err(|e| anyhow::anyhow!(\"Relay yamux session error: {e}\"))?;\n\n                tokio::spawn(async move {\n                    if let Err(error) = handle_inbound_stream(stream, local_addr).await {\n                        tracing::warn!(?error, \"Relay stream handling failed\");\n                    }\n                });\n            }\n        }\n    }\n}\n\nasync fn handle_inbound_stream(\n    stream: tokio_yamux::StreamHandle,\n    local_addr: SocketAddr,\n) -> anyhow::Result<()> {\n    let io = TokioIo::new(stream);\n\n    server_http1::Builder::new()","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/crates/relay-tunnel-core/src/client.rs#L48-L84","documentation":"In the same select! loop, session.next() can yield Some(Err(e)) where e is a yamux protocol/session error (stream reset, invalid frame, connection broken). The code maps that error into 'Relay yamux session error: {e}'. It signals the multiplexed session is corrupt or the transport failed mid-stream.","triggerScenarios":"Underlying WebSocket to the relay breaks mid-session, yamux frame corruption/protocol violation, stream resets, or the remote abruptly resets the TCP connection carrying the multiplexed session.","commonSituations":"Unstable networks (mobile, hotel Wi-Fi) dropping long-lived tunnels; firewalls/NAT killing idle connections; relay server under memory pressure resetting streams; yamux version mismatches between client and server.","solutions":["Reconnect the relay client with exponential backoff; the session is not recoverable once yamux errors out.","Inspect the wrapped '{e}' to distinguish transport drops (reconnect) from protocol bugs (fix version mismatch).","Enable yamux keepalives and shorter idle timeouts so dead connections are detected and re-established promptly.","Check relay server logs around the same timestamp for the peer-side error."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match start_relay(...).await {\n    Err(e) if e.to_string().contains(\"Relay yamux session error\") => {\n        tracing::warn!(?e, \"yamux session broke; reconnecting\");\n        backoff_retry(|| start_relay(...)).await?;\n    }\n    other => other?,\n}","preventionTips":["Use reconnect-with-backoff around the relay client lifecycle.","Keep client/server yamux versions and configs in sync.","Keep NAT/firewall sessions alive with heartbeats.","Log the inner yamux error to distinguish transport vs protocol causes."],"tags":["network","relay","yamux","protocol"],"backgroundTag":"yamux-session-error","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}