{"record":{"id":"64038131aed01f38","repo":"zeroclaw-labs/zeroclaw","slug":"mattermost-websocket-ended-during-authentication","errorCode":null,"errorMessage":"Mattermost WebSocket ended during authentication","messagePattern":"Mattermost WebSocket ended during authentication","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/mattermost.rs","lineNumber":466,"sourceCode":"                        Some(Ok(WsMessage::Text(text))) => text,\n                        Some(Ok(WsMessage::Ping(payload))) => {\n                            write\n                                .send(WsMessage::Pong(payload))\n                                .await\n                                .context(\"Mattermost WebSocket handshake pong failed\")?;\n                            continue;\n                        }\n                        Some(Ok(WsMessage::Close(frame))) => {\n                            let reason = frame\n                                .as_ref()\n                                .map(|frame| frame.reason.as_ref())\n                                .unwrap_or(\"\");\n                            bail!(\"Mattermost WebSocket closed during authentication: {reason}\");\n                        }\n                        Some(Err(error)) => {\n                            return Err(error).context(\"Mattermost WebSocket handshake read failed\");\n                        }\n                        None => bail!(\"Mattermost WebSocket ended during authentication\"),\n                        Some(Ok(_)) => continue,\n                    };\n\n                    let event: serde_json::Value = serde_json::from_str(text.as_ref())\n                        .context(\"Mattermost WebSocket handshake returned invalid JSON\")?;\n\n                    if let Some(ok) = Self::ws_auth_response(&event, auth_seq) {\n                        if !ok {\n                            bail!(\"Mattermost WebSocket authentication was rejected\");\n                        }\n                        authenticated = true;\n                    }\n\n                    if event.get(\"event\").and_then(|value| value.as_str()) == Some(\"hello\") {\n                        server_version = Some(\n                            event\n                                .get(\"data\")\n                                .and_then(|data| data.get(\"server_version\"))","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/mattermost.rs#L448-L484","documentation":"During WebSocket authentication the read stream returned `None` — the connection ended without a Close frame. The socket vanished silently, which typically means a dropped TCP connection or an intermediary cutting it, rather than a server-initiated close.","triggerScenarios":"During `authenticate_websocket`: network drop, NAT/firewall reset, proxy killing the fresh socket, or the Mattermost process dying before the handshake completes.","commonSituations":"Flaky networks and VPNs; containers restarting mid-connect; aggressive connection-level firewall rules.","solutions":["Retry with backoff — most silent ends during handshake are transient","Test TCP stability to the Mattermost host (long curl or mtr)","Check proxy idle-timeout and reset behavior on new WebSocket connections"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"Err(e) if e.to_string().contains(\"ended during authentication\") => {\n    // silent stream end: reconnect with backoff\n    tokio::time::sleep(backoff.next()).await;\n    continue;\n}","preventionTips":["Include silent handshake drops in the same reconnect policy as closes","Track connection failure rates per channel to distinguish environment issues from config issues","Avoid handshake retries without backoff — rapid reconnect loops can trip server throttling"],"tags":["mattermost","websocket","handshake","connection-reset","rust"],"backgroundTag":"websocket-connection-closed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}