BloopAI/vibe-kanban · error

relay session error: {error}

Error message

relay session error: {error}

What it means

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.

Source

Thrown at crates/relay-tunnel-core/src/server.rs:41

/// shared control handle that can be used to proxy requests over new streams.
pub async fn run_control_channel<F, Fut>(socket: WebSocket, on_connected: F) -> anyhow::Result<()>
where
    F: FnOnce(SharedControl) -> Fut,
    Fut: Future<Output = ()>,
{
    let ws_io = axum_ws_stream_io(socket);
    let mut session = Session::new_server(ws_io, yamux_config());
    let control = Arc::new(Mutex::new(session.control()));

    on_connected(control).await;

    while let Some(stream_result) = session.next().await {
        match stream_result {
            Ok(_stream) => {
                // The client side does not currently open server-initiated streams.
            }
            Err(error) => {
                return Err(anyhow::anyhow!("relay session error: {error}"));
            }
        }
    }

    Ok(())
}

/// Proxies one HTTP request over a new yamux stream using the shared control.
pub async fn proxy_request_over_control(
    control: &Mutex<Control>,
    request: Request,
    strip_prefix: &str,
) -> Response {
    let stream = {
        let mut control = control.lock().await;
        match control.open_stream().await {
            Ok(stream) => stream,
            Err(error) => {

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Treat as a client-side connection issue: have the client reconnect; the server will accept a new control channel.
  2. Inspect '{error}' and server logs to distinguish transient transport drops from protocol violations.
  3. Raise proxy/load-balancer idle timeouts so long-lived control channels aren't severed.
  4. Ensure client and server use compatible yamux versions and keepalive settings.
Defensive patterns

Strategy: try-catch

Try / catch

// at the handle_control_channel boundary
if let Err(e) = run_control_channel(session, ...).await {
    tracing::warn!(error=?e, "control channel ended; awaiting client reconnect");
    // do not crash the server; the client will re-establish
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/af0331c1eca4b335. Report an issue: GitHub.