{"record":{"id":"5f728fa64bdb19dd","repo":"zeroclaw-labs/zeroclaw","slug":"mattermost-websocket-idle-for-seconds","errorCode":null,"errorMessage":"Mattermost WebSocket idle for {} seconds","messagePattern":"Mattermost WebSocket idle for (.+?) seconds","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/mattermost.rs","lineNumber":1132,"sourceCode":"                    };\n\n                    if self\n                        .process_inbound_post(\n                            &post,\n                            &bot_user_id,\n                            &bot_username,\n                            0,\n                            channel_id,\n                            is_direct,\n                            &tx,\n                        )\n                        .await\n                    {\n                        return Ok(());\n                    }\n                }\n                _ = tokio::time::sleep_until(read_deadline) => {\n                    bail!(\n                        \"Mattermost WebSocket idle for {} seconds\",\n                        WS_READ_TIMEOUT.as_secs()\n                    );\n                }\n            }\n        }\n    }\n}\n\nimpl MattermostChannel {\n    #[allow(clippy::too_many_arguments)]\n    async fn process_inbound_post(\n        &self,\n        post: &serde_json::Value,\n        bot_user_id: &str,\n        bot_username: &str,\n        last_create_at: i64,\n        channel_id: &str,","sourceCodeStart":1114,"sourceCodeEnd":1150,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/mattermost.rs#L1114-L1150","documentation":"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.","triggerScenarios":"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.","commonSituations":"Reverse proxies buffering WebSocket traffic; NAT/mobile networks dropping idle sockets; overloaded servers pausing pings.","solutions":["Reconnect — the dead connection is the problem, not the timeout","Ensure the proxy passes WebSocket frames transparently (no buffering) and its idle timeout exceeds the ping interval","Keep client-side keepalive enabled if configurable","Only raise the timeout when the network is known-slow; masking real drops makes the bot look hung"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"Err(e) if e.to_string().contains(\"WebSocket idle for\") => {\n    // half-open connection: reconnect immediately with fresh handshake\n    continue;\n}","preventionTips":["Let the built-in idle timeout do its job — reconnect instead of raising the limit first","Verify proxies forward ping/pong frames and do not buffer WebSocket traffic","Monitor idle-timeout frequency to detect degrading network paths early"],"tags":["mattermost","websocket","idle-timeout","rust"],"backgroundTag":"websocket-idle-timeout","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}