Skip to content

fix(mattermost): use inbound root_id to correct non-root replyToId (closes #30977)#1456

Open
BingqingLyu wants to merge 1 commit intomainfrom
fork-pr-55151-fix-mattermost-inbound-root-id-30977
Open

fix(mattermost): use inbound root_id to correct non-root replyToId (closes #30977)#1456
BingqingLyu wants to merge 1 commit intomainfrom
fork-pr-55151-fix-mattermost-inbound-root-id-30977

Conversation

@BingqingLyu
Copy link
Copy Markdown
Owner

@BingqingLyu BingqingLyu commented Apr 27, 2026

Summary

  • When replyToMode is "off" for DMs, effectiveReplyToId is always undefined
  • The core reply dispatcher sets payload.replyToId to the inbound message's own ID (via applyReplyThreading / [[reply-to:current]])
  • For thread replies, this ID is a non-root post — Mattermost rejects it with 400 Invalid RootId parameter because root_id must reference the thread's actual root post
  • Adds inboundRootId parameter to resolveMattermostReplyRootId carrying the inbound post's root_id, which is always a valid thread root when set

Resolution order:

  1. threadRootId — effectiveReplyToId from replyToMode / thread context
  2. inboundRootId — the inbound post's root_id (always a valid root)
  3. replyToId — agent/directive-supplied (may be non-root; last resort)

Reproduction

  1. DM the bot with a top-level message (post A)
  2. Bot replies in thread (post B, root_id=A)
  3. User replies in thread (post C, root_id=A)
  4. Core dispatcher sets payload.replyToId = C (non-root post)
  5. resolveMattermostReplyRootId falls through to replyToId = C400 Bad Request

With this fix, step 5 resolves to inboundRootId = A (the valid thread root).

Test plan

  • Added regression test: inboundRootId takes priority over non-root replyToId when threadRootId is absent
  • Added test: threadRootId still takes priority over inboundRootId
  • Added test: falls back to replyToId when both are absent (top-level message)
  • Existing tests pass unchanged
  • All 3 call sites updated to pass inboundRootId

Closes openclaw#30977

🤖 Generated with Claude Code

…Id (openclaw#30977)

When `replyToMode` is "off" for DMs, `effectiveReplyToId` is always
undefined.  The core reply dispatcher sets `payload.replyToId` to the
inbound message's own ID (via `applyReplyThreading` /
`[[reply-to:current]]`).  For thread replies this ID is a non-root post,
which Mattermost rejects with 400 "Invalid RootId parameter" — because
`root_id` must reference the thread's actual root post.

Add an `inboundRootId` parameter to `resolveMattermostReplyRootId` that
carries the inbound post's `root_id`.  Resolution order:

  1. `threadRootId` (effectiveReplyToId from replyToMode / thread context)
  2. `inboundRootId` (the inbound post's root_id — always a valid root)
  3. `replyToId` (agent/directive-supplied — may be non-root; last resort)

This ensures thread replies in DMs use the correct root post ID while
preserving existing behaviour for top-level messages and channels with
`replyToMode` enabled.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mattermost: Invalid RootId when reply_to_current targets a threaded reply

2 participants