-
Notifications
You must be signed in to change notification settings - Fork 137
Description
Bug
Direct messages to a bot fail with invalid_thread_ts (from chat.postMessage) and invalid_arguments (from chatStream) because handleMessageEvent sets threadTs = "" for top-level DM messages.
Root Cause
In @chat-adapter/slack, handleMessageEvent computes threadTs differently for DMs vs channels:
const threadTs = isDM ? event.thread_ts || "" : event.thread_ts || event.ts;For channels, top-level messages fall back to event.ts (a valid Slack timestamp).
For DMs, top-level messages fall back to "" (empty string).
This empty string propagates through encodeThreadId → decodeThreadId → Slack API calls:
| Method | What happens | Slack error |
|---|---|---|
postMessage |
thread_ts: "" |
invalid_thread_ts |
chatStream |
thread_ts: "" |
invalid_arguments |
startTyping |
Silently skipped (if (!threadTs) return) |
No error but no typing indicator |
postEphemeral |
Works — already uses threadTs || void 0 |
✅ |
Reproduction
- Create a bot using
chat+@chat-adapter/slack - Register an
onNewMentionhandler that callsthread.post("hello") - Send a DM to the bot (not in a channel)
- Observe:
An API error occurred: invalid_thread_ts - If using streaming (
thread.post(result.fullStream)):An API error occurred: invalid_arguments
Channel mentions work fine because they fall back to event.ts.
Fix
Use the same fallback for both DMs and channels:
// Before (broken for DMs):
const threadTs = isDM ? event.thread_ts || "" : event.thread_ts || event.ts;
// After (works for both):
const threadTs = event.thread_ts || event.ts;Additionally, postMessage and chatStream should defensively guard against empty threadTs (like postEphemeral already does):
// postMessage — 3 code paths
thread_ts: threadTs || void 0,
// chatStream
thread_ts: threadTs || void 0,Workaround
We're using pnpm patch @chat-adapter/slack to apply both fixes. Happy to open a PR if preferred.
Versions
chat: 4.20.2@chat-adapter/slack: 4.20.2- Bug also present in 4.18.0