From ea34aadfe091f01fe21013dc1c7b2babc16d35c8 Mon Sep 17 00:00:00 2001 From: e2e Date: Fri, 28 Aug 2026 08:59:06 -0500 Subject: [PATCH] fix(gateway): keep Matrix password-auth in the reconnect retry queue _platform_has_bot_credential() decides whether a failed platform may be retried. It only inspected PlatformConfig.token / .api_key, but Matrix supports password login (MATRIX_USER_ID + MATRIX_PASSWORD, no MATRIX_ACCESS_TOKEN), and build_config() puts those on extra{} rather than .token. So a password-auth Matrix config read as credential-less, and the reconnect watcher deleted it from the retry queue on the first transient failure. A momentary DNS failure at boot therefore took Matrix down permanently: the homeserver was healthy, but nothing ever retried and recovery required a manual gateway restart. Observed live as a ~13h outage after a boot-time "Temporary failure in name resolution". Mirror the adapter's own gate (homeserver + user_id + password). Read ONLY from extra, never os.getenv: build_config() already copies all three env vars onto extra, and importing this module loads ~/.hermes/.env, so an env fallback would report "has credential" for every Matrix config on the host -- including the empty-primary multiplex case (#64674) that this check exists to evict. Co-Authored-By: Claude Opus 5 --- gateway/run.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/gateway/run.py b/gateway/run.py index c35593ab8b..5ff6322e22 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -2624,7 +2624,7 @@ def _platform_has_bot_credential(platform: "Platform", platform_config: "Platfor Platforms that do not use ``PlatformConfig.token`` always return True so we never skip them here (Signal session paths, port-binding HTTP adapters, etc.). """ - from gateway.config import PLATFORM_TOKEN_ENV_NAMES + from gateway.config import PLATFORM_TOKEN_ENV_NAMES, Platform if platform not in PLATFORM_TOKEN_ENV_NAMES: return True @@ -2635,6 +2635,26 @@ def _platform_has_bot_credential(platform: "Platform", platform_config: "Platfor api_key = getattr(platform_config, "api_key", None) or "" if isinstance(api_key, str) and api_key.strip(): return True + # Matrix also authenticates by password login (MATRIX_USER_ID + + # MATRIX_PASSWORD, no MATRIX_ACCESS_TOKEN). Those credentials land in + # ``extra`` rather than ``.token``, so a token-only check reads a + # perfectly reconnectable password-auth config as credential-less and + # evicts it from the retry queue on the first transient failure — after + # which it stays down until the gateway is restarted by hand. Mirror the + # adapter's own gate: homeserver + user_id + password. + # + # Read ONLY from extra, never os.getenv: build_config() already copies all + # three env vars onto extra, and importing this module loads ~/.hermes/.env, + # so an env fallback would report "has credential" for every Matrix config + # on the box — including the empty-primary multiplex case (#64674) this + # check exists to evict. + if platform is Platform.MATRIX: + extra = getattr(platform_config, "extra", None) or {} + if all( + str(extra.get(key) or "").strip() + for key in ("homeserver", "user_id", "password") + ): + return True return False