Skip to content

fix(slack): queue drain drops string thread_ts — replies leak to main channel instead of thread#11194

Closed
Lukavyi wants to merge 1 commit intoopenclaw:mainfrom
Lukavyi:fix/slack-string-thread-id-queue-drain
Closed

fix(slack): queue drain drops string thread_ts — replies leak to main channel instead of thread#11194
Lukavyi wants to merge 1 commit intoopenclaw:mainfrom
Lukavyi:fix/slack-string-thread-id-queue-drain

Conversation

@Lukavyi
Copy link
Copy Markdown
Contributor

@Lukavyi Lukavyi commented Feb 7, 2026

Summary

Queue drain uses typeof threadId === "number" which silently drops Slack's string thread_ts, causing queued replies to leak to the main channel instead of the thread.

lobster-biscuit

Repro Steps

  1. Configure Slack with replyToMode: all
  2. Send 2+ messages while agent is processing
  3. Queued response appears in channel, not thread

Root Cause

src/auto-reply/reply/queue/drain.ts uses typeof threadId === "number" in 3 places. Telegram uses numeric topic IDs (passes check), Slack uses string thread_ts like "1770474140.187459" (fails check). The type in queue/types.ts was updated to string | number when Slack threading was added, but drain.ts was not updated.

Behavior Changes

  • String thread IDs (Slack thread_ts) now preserved during queue drain
  • Empty string "" treated as absent (prevents spurious thread grouping if any provider normalizes missing values to "")
  • No change for numeric thread IDs (Telegram)

Codebase and GitHub Search

Tests

3 new cases in queue.collect-routing.test.ts:

  • ✅ Collects messages with matching string thread_ts (same Slack thread)
  • ✅ Separates messages with different string thread_ts (different threads)
  • ✅ Treats empty string threadId same as absent
pnpm test src/auto-reply/reply/queue.collect-routing.test.ts
 ✓ 9 tests passed

Sign-Off

Fixes #11195
Related PRs (same fix, but without empty-string edge case protection):

This PR adds \&\& threadId !== "" to all 3 locations, addressing the edge case Greptile identified. Also includes 3 new tests (string thread_ts collection, different threads separation, empty-string handling) which the other PRs lack.

Related issues: #4380, #4424, #5615


Greptile Overview

Greptile Summary

This PR fixes follow-up queue drain routing so Slack thread replies don't lose their thread_ts context during "collect" drains.

The drain logic previously treated originatingThreadId as present only when it was a number, which works for Telegram topic IDs but drops Slack's string thread_ts values. The change updates the routing key computation and the collected-batch originatingThreadId selection to treat any non-empty string | number as a valid thread id, while treating "" as absent to avoid creating spurious thread groups. New tests in queue.collect-routing.test.ts cover same-thread collection, different-thread separation, and empty-string behavior.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk.
  • Changes are narrowly scoped to queue drain routing, align with existing FollowupRun.originatingThreadId: string | number typing, and are covered by targeted unit tests for Slack thread_ts string handling and empty-string edge cases.
  • No files require special attention

Greptile review restored manually after accidental body overwrite.

…d reply leaks

The queue drain logic used `typeof threadId === 'number'` to check for
thread IDs, which silently dropped Slack's string-based thread_ts values
(e.g. '1770474140.187459'). This caused queued thread replies to lose
their thread context and leak into the main channel.

Replace type-narrowing checks with `threadId != null && threadId !== ''`
to support both numeric (Telegram topic IDs) and string (Slack thread_ts)
thread identifiers.

Also treats empty string threadId as absent to prevent incorrect grouping
when providers normalize missing values to ''.

Fixes openclaw#4380
@openclaw-barnacle
Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Feb 21, 2026
@vincentkoc
Copy link
Copy Markdown
Member

Thanks for digging into this queue-drain bug.

Closing as superseded by merged #23804, which already carries the string thread_ts preservation path on current main.

If you still see leakage after latest main, reply with a repro and we can reopen quickly.

@vincentkoc vincentkoc closed this Feb 22, 2026
@vincentkoc vincentkoc added dedupe:child Duplicate issue/PR child in dedupe cluster close:duplicate Closed as duplicate labels Feb 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

close:duplicate Closed as duplicate dedupe:child Duplicate issue/PR child in dedupe cluster stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Slack queue drain drops string thread_ts — queued replies leak to main channel instead of thread

2 participants