fix(gateway): stop Matrix/Mattermost reconnect on permanent auth failures

Cherry-picked from PR #3695 by binhnt92.
Matrix _sync_loop() and Mattermost _ws_loop() were retrying all errors
forever, including permanent auth failures (expired tokens, revoked
access). Now detects M_UNKNOWN_TOKEN, M_FORBIDDEN, 401/403 and stops
instead of spinning. Includes 216 lines of tests.
This commit is contained in:
binhnt92
2026-04-05 10:44:39 -07:00
committed by Teknium
parent 9d7c288d86
commit b65e67545a
3 changed files with 239 additions and 0 deletions

View File

@@ -684,6 +684,13 @@ class MatrixAdapter(BasePlatformAdapter):
if isinstance(resp, nio.SyncError):
if self._closing:
return
err_msg = str(getattr(resp, "message", resp)).lower()
if "m_unknown_token" in err_msg or "m_forbidden" in err_msg or "401" in err_msg:
logger.error(
"Matrix: permanent auth error from sync: %s — stopping sync",
getattr(resp, "message", resp),
)
return
logger.warning(
"Matrix: sync returned %s: %s — retrying in 5s",
type(resp).__name__,
@@ -698,6 +705,12 @@ class MatrixAdapter(BasePlatformAdapter):
except Exception as exc:
if self._closing:
return
# Detect permanent auth/permission failures that will never
# succeed on retry — stop syncing instead of looping forever.
err_str = str(exc).lower()
if "401" in err_str or "403" in err_str or "unauthorized" in err_str or "forbidden" in err_str:
logger.error("Matrix: permanent auth error: %s — stopping sync", exc)
return
logger.warning("Matrix: sync error: %s — retrying in 5s", exc)
await asyncio.sleep(5)

View File

@@ -513,6 +513,16 @@ class MattermostAdapter(BasePlatformAdapter):
except Exception as exc:
if self._closing:
return
# Detect permanent auth/permission failures that will never
# succeed on retry — stop reconnecting instead of looping forever.
import aiohttp
err_str = str(exc).lower()
if isinstance(exc, aiohttp.WSServerHandshakeError) and exc.status in (401, 403):
logger.error("Mattermost WS auth failed (HTTP %d) — stopping reconnect", exc.status)
return
if "401" in err_str or "403" in err_str or "unauthorized" in err_str:
logger.error("Mattermost WS permanent error: %s — stopping reconnect", exc)
return
logger.warning("Mattermost WS error: %s — reconnecting in %.0fs", exc, delay)
if self._closing: