{"record":{"id":"00cb1ac69307bb36","repo":"zeroclaw-labs/zeroclaw","slug":"mattermost-websocket-authentication-was-rejected","errorCode":null,"errorMessage":"Mattermost WebSocket authentication was rejected","messagePattern":"Mattermost WebSocket authentication was rejected","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/mattermost.rs","lineNumber":475,"sourceCode":"                            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\"))\n                                .and_then(|value| value.as_str())\n                                .unwrap_or(\"unknown\")\n                                .to_string(),\n                        );\n                    }\n                }\n            }\n        }\n    }","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/mattermost.rs#L457-L493","documentation":"The Mattermost WebSocket handshake completed, and the server explicitly answered the auth challenge (`ws_auth_response` matched the auth sequence) with a rejection. This is a credential refusal over WebSocket — almost always an invalid, expired, or revoked token.","triggerScenarios":"`listen_websocket` authenticating with a bot_token or password-derived session token that the server refuses: revoked personal access token, expired login session, or a token from a different instance.","commonSituations":"Personal access token regenerated in Mattermost but config still holds the old one; session token invalidated by logout/password change; token copied with extra characters.","solutions":["Regenerate the personal access token and update `bot_token` in config","If using login_id/password, verify those credentials via REST login first","Sanity-check the token: `curl -H \"Authorization: Bearer <token>\" <server>/api/v4/users/me` must return the bot user"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"let resp = client\n    .get(format!(\"{base_url}/api/v4/users/me\"))\n    .bearer_auth(&token)\n    .send()\n    .await?;\nif !resp.status().is_success() {\n    return Err(anyhow::anyhow!(\"token rejected; refresh before starting WS listen\"));\n}","typeGuard":null,"tryCatchPattern":"match mm_channel.listen(tx).await {\n    Err(e) if e.to_string().contains(\"authentication was rejected\") => {\n        // fatal credential problem: refresh bot_token / re-login, then reconnect\n    }\n    other => other,\n}","preventionTips":["Pre-validate the token over REST before starting the WebSocket listener","Rotate tokens proactively and alert on auth rejections — retrying with a bad token cannot succeed","Keep token generation scripted so refreshes update config in one step"],"tags":["mattermost","websocket","auth","invalid-token","rust"],"backgroundTag":"invalid-auth-token","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}