Skip to content

fix(mattermost): use thread root_id from metadata for CRT Thread replies#28012

Open
colin-chang wants to merge 2 commits into
NousResearch:mainfrom
colin-chang:fix/mattermost-crt-root-id
Open

fix(mattermost): use thread root_id from metadata for CRT Thread replies#28012
colin-chang wants to merge 2 commits into
NousResearch:mainfrom
colin-chang:fix/mattermost-crt-root-id

Conversation

@colin-chang

Copy link
Copy Markdown
Contributor

Summary

Fixes a bug where Hermes replies fail with 400 Invalid RootId when MATTERMOST_REPLY_MODE=thread and the user sends a message from inside an existing CRT Thread.

Root Cause

gateway/platforms/mattermost.py line 272-274 used reply_to (the user's immediate message ID) as the root_id. In Mattermost CRT, when replying inside an existing Thread, root_id must point to the thread's root-level post, not a nested reply message. Using the user's own message ID — which is itself a reply — causes Mattermost to reject with 400.

The correct root_id is already available in metadata["thread_id"], set by _thread_metadata_for_source() based on post.root_id from the incoming WebSocket event.

Why top-level channel messages worked

When the user sends from the main channel (not in a Thread), their message IS a root-level post. Using reply_to as root_id is valid in that case. The bug only manifests inside existing CRT Threads.

Fix

-            # Thread support: reply_to is the root post ID.
+            # Thread support: use the thread's root_id from metadata when
+            # replying inside an existing CRT Thread. Mattermost requires
+            # root_id to point to the root-level post, not a nested reply.
+            # Fall back to reply_to for top-level channel messages (where
+            # the user's message itself is a valid thread root).
             if reply_to and self._reply_mode == "thread":
-                payload["root_id"] = reply_to
+                thread_root = (metadata or {}).get("thread_id")
+                payload["root_id"] = thread_root or reply_to

Testing

  • Reproduced on Mattermost 11.7.0 (Team Edition, Docker), MATTERMOST_REPLY_MODE=thread
  • Verified fix resolves all 400 errors in gateway logs
  • Verified top-level channel replies continue to work (fallback to reply_to when metadata is None)

Closes #28005

…sections to PlatformConfig

Setting `gateway_restart_notification: false` in config.yaml platform
sections (e.g. `discord:`, `telegram:`) was silently ignored — the
setting never reached the PlatformConfig object, so restart/shutdown
notifications were always sent regardless of the user's preference.

Root cause (two-part):
1. The shared-key bridging loop in load_gateway_config() omitted
   `gateway_restart_notification` from its bridge list, so the value
   from `discord:` YAML never entered `platforms_data`.
2. PlatformConfig.from_dict() only read the key from the top-level dict,
   not from `extra` where bridged values are stored.

Fix:
- Add `gateway_restart_notification` to the bridging loop so the YAML
  value propagates into `platforms_data["<plat>"].extra`.
- Update PlatformConfig.from_dict() to fall back to `extra` when the
  top-level key is absent, matching the pattern used by other bridged
  settings.

Regression tests added for both from_dict() extra-fallback and the
end-to-end load_gateway_config() bridging path.
When reply_mode=thread and a user sends from inside a CRT Thread,
the previous code used reply_to (user's message ID) as root_id.
In Mattermost CRT, root_id must point to the root-level post,
not a nested reply. Using the wrong ID causes 400 Invalid RootId.

Fix: use metadata['thread_id'] (set by _thread_metadata_for_source)
which correctly contains the Thread's root message ID.

Closes NousResearch#28005
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery labels May 18, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Fixes the specific CRT Thread scenario from #28005. Note: PR #20874 is a more comprehensive Mattermost threading fix that supersedes earlier attempts (#6617, #12096, #12299) and also addresses this root_id issue. Root issue: #12063.

@outsourc-e

Copy link
Copy Markdown
Contributor

I pulled this into a clean upstream/main worktree. The Mattermost CRT fix is good, but the branch is stacked with an unrelated gateway_restart_notification config fix. I opened a clean replacement PR with only the CRT-thread change plus focused regression coverage: #28192.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(mattermost): CRT Thread replies fail with 400 Invalid RootId when using reply_to as root_id

3 participants