diff --git a/gateway/platforms/mattermost.py b/gateway/platforms/mattermost.py index 574f465b1dd..6bfa6ac4372 100644 --- a/gateway/platforms/mattermost.py +++ b/gateway/platforms/mattermost.py @@ -249,6 +249,23 @@ class MattermostAdapter(BasePlatformAdapter): logger.info("Mattermost: disconnected") + + async def _resolve_root_id(self, post_id: str) -> str: + """Resolve a post_id to the thread root_id for Mattermost. + + Mattermost requires root_id to be the *root* post of a thread. + If the post is a reply (has its own root_id), we must use that + root_id instead. Using a reply's own ID as root_id causes + "Invalid RootId parameter" errors. + """ + if not post_id: + return post_id + # Check if this post has a root_id (meaning it's a reply) + data = await self._api_get(f"posts/{post_id}") + if data and data.get("root_id"): + return data["root_id"] + return post_id + async def send( self, chat_id: str, @@ -271,7 +288,10 @@ class MattermostAdapter(BasePlatformAdapter): } # Thread support: reply_to is the root post ID. if reply_to and self._reply_mode == "thread": - payload["root_id"] = reply_to + # Ensure root_id points to the thread root, not a reply. + # Mattermost rejects non-root post IDs as root_id. + resolved_root = await self._resolve_root_id(reply_to) + payload["root_id"] = resolved_root data = await self._api_post("posts", payload) if not data or "id" not in data: @@ -451,7 +471,7 @@ class MattermostAdapter(BasePlatformAdapter): "file_ids": [file_id], } if reply_to and self._reply_mode == "thread": - payload["root_id"] = reply_to + payload["root_id"] = await self._resolve_root_id(reply_to) data = await self._api_post("posts", payload) if not data or "id" not in data: @@ -490,7 +510,7 @@ class MattermostAdapter(BasePlatformAdapter): "file_ids": [file_id], } if reply_to and self._reply_mode == "thread": - payload["root_id"] = reply_to + payload["root_id"] = await self._resolve_root_id(reply_to) data = await self._api_post("posts", payload) if not data or "id" not in data: diff --git a/gateway/run.py b/gateway/run.py index 8a25c7a441b..9512060d7cb 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -15063,7 +15063,7 @@ class GatewayRunner: ) if _progress_thread_id else None _progress_reply_to = ( event_message_id - if source.platform == Platform.FEISHU and source.thread_id and event_message_id + if source.platform in (Platform.FEISHU, Platform.MATTERMOST) and source.thread_id and event_message_id else None )