zeroclaw-labs/zeroclaw · error · anyhow::Error

Mattermost WebSocket idle for {} seconds

Error message

Mattermost WebSocket idle for {} seconds

What it means

The listener enforces a read deadline (`WS_READ_TIMEOUT`) and resets it on every frame. Mattermost normally sends pings every ~30 seconds, so silence for the full timeout means a half-open connection or a path that drops WebSocket control frames. The connection is presumed dead and the error is raised so the caller reconnects.

Source

Thrown at crates/zeroclaw-channels/src/mattermost.rs:1132

                    };

                    if self
                        .process_inbound_post(
                            &post,
                            &bot_user_id,
                            &bot_username,
                            0,
                            channel_id,
                            is_direct,
                            &tx,
                        )
                        .await
                    {
                        return Ok(());
                    }
                }
                _ = tokio::time::sleep_until(read_deadline) => {
                    bail!(
                        "Mattermost WebSocket idle for {} seconds",
                        WS_READ_TIMEOUT.as_secs()
                    );
                }
            }
        }
    }
}

impl MattermostChannel {
    #[allow(clippy::too_many_arguments)]
    async fn process_inbound_post(
        &self,
        post: &serde_json::Value,
        bot_user_id: &str,
        bot_username: &str,
        last_create_at: i64,
        channel_id: &str,

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Reconnect — the dead connection is the problem, not the timeout
  2. Ensure the proxy passes WebSocket frames transparently (no buffering) and its idle timeout exceeds the ping interval
  3. Keep client-side keepalive enabled if configurable
  4. Only raise the timeout when the network is known-slow; masking real drops makes the bot look hung
Defensive patterns

Strategy: retry

Try / catch

Err(e) if e.to_string().contains("WebSocket idle for") => {
    // half-open connection: reconnect immediately with fresh handshake
    continue;
}

Prevention

When it happens

Trigger: During `listen_websocket`: the network black-holes frames, a proxy buffers or strips ping/pong frames, or the server stops sending pings under load; the `sleep_until(read_deadline)` branch of the select wins.

Common situations: Reverse proxies buffering WebSocket traffic; NAT/mobile networks dropping idle sockets; overloaded servers pausing pings.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/5f728fa64bdb19dd. Report an issue: GitHub.