zeroclaw-labs/zeroclaw · error · anyhow::Error
Mattermost WebSocket closed during authentication: {reason}
Error message
Mattermost WebSocket closed during authentication: {reason} What it means
While authenticating the Mattermost WebSocket, the server sent a Close frame; its reason string is included in the error. This is the server (or an intermediary) actively ending the connection mid-handshake, as opposed to the deadline timeout.
Source
Thrown at crates/zeroclaw-channels/src/mattermost.rs:461
_ = tokio::time::sleep_until(deadline) => {
bail!("Mattermost WebSocket authentication handshake timed out");
}
frame = read.next() => {
let text = match frame {
Some(Ok(WsMessage::Text(text))) => text,
Some(Ok(WsMessage::Ping(payload))) => {
write
.send(WsMessage::Pong(payload))
.await
.context("Mattermost WebSocket handshake pong failed")?;
continue;
}
Some(Ok(WsMessage::Close(frame))) => {
let reason = frame
.as_ref()
.map(|frame| frame.reason.as_ref())
.unwrap_or("");
bail!("Mattermost WebSocket closed during authentication: {reason}");
}
Some(Err(error)) => {
return Err(error).context("Mattermost WebSocket handshake read failed");
}
None => bail!("Mattermost WebSocket ended during authentication"),
Some(Ok(_)) => continue,
};
let event: serde_json::Value = serde_json::from_str(text.as_ref())
.context("Mattermost WebSocket handshake returned invalid JSON")?;
if let Some(ok) = Self::ws_auth_response(&event, auth_seq) {
if !ok {
bail!("Mattermost WebSocket authentication was rejected");
}
authenticated = true;
}
View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the close reason in the message — it usually names the cause
- Retry once; closes during server deploys are common and self-healing
- Verify `base_url` and that `<server>/api/v4/websocket` is the endpoint being hit
- Check Mattermost server logs at the close timestamp
Defensive patterns
Strategy: retry
Try / catch
match mm_channel.listen(tx).await {
Err(e) if e.to_string().contains("closed during authentication") => {
// server-initiated close mid-handshake: reconnect with backoff;
// if the reason mentions auth, refresh the token instead
}
other => other,
} Prevention
- Reconnect with backoff on handshake closes; treat repeated closes as a server/proxy problem
- Log and inspect the close reason string before choosing retry vs re-auth
- Keep base_url pointed at the WebSocket-capable endpoint
When it happens
Trigger: During `authenticate_websocket`: the server closes the socket after connect — auth policy rejection, wrong WebSocket endpoint/path, Mattermost shutting down, or a proxy tearing down the upgraded connection.
Common situations: Misrouted `base_url` so the WS handshake lands on the wrong endpoint; Mattermost restart during connect; proxy or LB killing new WebSocket connections; server-side session invalidation.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Mattermost WebSocket authentication handshake timed out
- Mattermost WebSocket ended during authentication
- Mattermost WebSocket closed: {reason}
- Mattermost WebSocket authentication was rejected
- Mattermost WebSocket stream ended
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/ce49d1e4e4062f26.
Report an issue: GitHub.