-
-
Notifications
You must be signed in to change notification settings - Fork 69.2k
Mattermost: block streaming + threading produces duplicate messages (one threaded, one top-level) #41219
Description
Bug description
When block streaming is enabled for Mattermost (the default — blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 }), agent replies to top-level channel messages produce two separate messages: one in the channel (top-level) and one threaded on the original message. These are different Mattermost posts with different content.
Root cause
Introduced in 2026.3.8 by #27744 (fix(mattermost): pass payload.replyToId as root_id for threaded replies). That commit correctly made the deliver callback pass payload.replyToId through via resolveMattermostReplyRootId(), but it exposed a latent inconsistency in how the block streaming and final payload paths handle threading:
-
Block streaming path (
createBlockReplyDeliveryHandler) sends coalesced chunks withreplyToIdset becauseresolveReplyToModefalls back to"all"for Mattermost (nothreadingdock defined). Thedelivercallback then threads them viaresolveMattermostReplyRootId. -
Final payload path (
buildReplyPayloads) —shouldDropFinalPayloadsis supposed to suppress final payloads when streaming succeeded, but when streaming partially works or aborts, the fallback deduplication usescreateBlockReplyPayloadKeywhich includesreplyToIdin the key. IfreplyToIddiffers between the block-streamed payload and the final payload, deduplication fails and both get delivered — one threaded, one top-level.
Contributing factors
- Missing
threadingdock: Mattermost's plugin dock has nothreadingsection, soresolveReplyToModefalls through to the hardcoded default"all". Telegram and Discord both explicitly define theirs as"off". replyToIdin payload dedup key:createBlockReplyPayloadKeyincludesreplyToId, treating identical content with different threading targets as separate payloads.- No
replyToModeconfig field: Mattermost's config schema doesn't includereplyToMode, so users can't control threading behavior.
Repro steps
- Configure a Mattermost channel with default settings (block streaming enabled)
- Post a message in a public channel mentioning the bot
- Observe: bot sends a threaded reply AND a separate top-level reply to the channel
Expected behavior
Bot should send a single reply (threaded on the original message when replyToMode is "all").
Affected version
2026.3.8+ (introduced by #27744)
Fix plan
- Add
threadingsection to the Mattermost plugin dock withresolveReplyToModereading fromchannels.mattermost.replyToModeconfig (default:"all") - Add
replyToModeto the Mattermost config schema - Remove
replyToIdfromcreateBlockReplyPayloadKey— threading is a delivery concern, not content identity; identical content shouldn't be sent twice because of different threading targets - Add tests covering block streaming + threading dedup and
resolveMattermostReplyRootIdwith block streaming payloads