{"record":{"id":"af0331c1eca4b335","repo":"BloopAI/vibe-kanban","slug":"relay-session-error-error","errorCode":null,"errorMessage":"relay session error: {error}","messagePattern":"relay session error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/relay-tunnel-core/src/server.rs","lineNumber":41,"sourceCode":"/// shared control handle that can be used to proxy requests over new streams.\npub async fn run_control_channel<F, Fut>(socket: WebSocket, on_connected: F) -> anyhow::Result<()>\nwhere\n    F: FnOnce(SharedControl) -> Fut,\n    Fut: Future<Output = ()>,\n{\n    let ws_io = axum_ws_stream_io(socket);\n    let mut session = Session::new_server(ws_io, yamux_config());\n    let control = Arc::new(Mutex::new(session.control()));\n\n    on_connected(control).await;\n\n    while let Some(stream_result) = session.next().await {\n        match stream_result {\n            Ok(_stream) => {\n                // The client side does not currently open server-initiated streams.\n            }\n            Err(error) => {\n                return Err(anyhow::anyhow!(\"relay session error: {error}\"));\n            }\n        }\n    }\n\n    Ok(())\n}\n\n/// Proxies one HTTP request over a new yamux stream using the shared control.\npub async fn proxy_request_over_control(\n    control: &Mutex<Control>,\n    request: Request,\n    strip_prefix: &str,\n) -> Response {\n    let stream = {\n        let mut control = control.lock().await;\n        match control.open_stream().await {\n            Ok(stream) => stream,\n            Err(error) => {","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/crates/relay-tunnel-core/src/server.rs#L23-L59","documentation":"The relay server's run_control_channel iterates inbound streams from the client's yamux session. Since clients do not open server-initiated streams in the current design, any Err from session.next() is fatal for that control channel and is returned as 'relay session error: {error}'. The handler then tears down the control connection.","triggerScenarios":"A yamux protocol error occurs on the server side of the control channel: transport read/write failure, frame corruption, stream reset, or the client's connection dying unexpectedly while the server drains the session.","commonSituations":"Client crashes or network drops mid-session; relay server behind a proxy/load balancer with short idle timeouts; TLS/WebSocket layer errors surfacing as yamux errors; client-server yamux configuration mismatch.","solutions":["Treat as a client-side connection issue: have the client reconnect; the server will accept a new control channel.","Inspect '{error}' and server logs to distinguish transient transport drops from protocol violations.","Raise proxy/load-balancer idle timeouts so long-lived control channels aren't severed.","Ensure client and server use compatible yamux versions and keepalive settings."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// at the handle_control_channel boundary\nif let Err(e) = run_control_channel(session, ...).await {\n    tracing::warn!(error=?e, \"control channel ended; awaiting client reconnect\");\n    // do not crash the server; the client will re-establish\n}","preventionTips":["Keep control-channel errors contained per-connection; never crash the relay server.","Set proxy/LB idle timeouts above the control channel keepalive interval.","Keep client and server yamux configurations compatible.","Correlate server-side errors with client reconnect logs."],"tags":["network","relay","server","yamux"],"backgroundTag":"yamux-session-error","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}