#22096: fix(slack): traverse .original for Slack SDK errors; pass recipient_team_id to streaming
channel: slack
size: S
Cluster:
Block Streaming Enhancements
## Summary
Two related Slack stability fixes found while debugging production crashes.
### Bug 1: Gateway crashes on transient Slack SDK network errors
**Root cause:** `@slack/web-api`'s `WebAPIRequestError` wraps the original network error in `.original` (not `.cause`). The existing `isTransientNetworkError()` only traverses `.cause`, so errors like `ECONNRESET` or `ETIMEDOUT` wrapped by the Slack SDK were not recognised as transient — causing `process.exit(1)` on routine reconnect failures.
**Fix:** Added `getWrappedOriginal()` helper and traverse `.original` in `isTransientNetworkError()`.
### Bug 2: `missing_recipient_team_id` when streaming in DM threads
**Root cause:** `chat.startStream` requires `recipient_team_id` when streaming in a DM thread, but `client.chatStream()` in `startSlackStream()` never passed it. This caused streaming to fail with `slack-stream: streaming API call failed: Error: An API error occurred: missing_recipient_team_id` and fall back to non-streaming delivery.
**Fix:** Added optional `recipientTeamId` to `StartSlackStreamParams` and forward it as `recipient_team_id`. Updated `dispatchPreparedSlackMessage` to pass `ctx.teamId`.
## Tests
Added unit tests for the `.original` traversal case in `unhandled-rejections.test.ts`.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR fixes two production stability issues in the Slack integration. The first fix prevents gateway crashes by correctly traversing the `@slack/web-api` SDK's `.original` error property to detect transient network errors (like `ECONNRESET`, `ETIMEDOUT`) that were previously causing `process.exit(1)`. The second fix resolves `missing_recipient_team_id` errors when streaming in DM threads by passing the team ID parameter required by Slack's streaming API.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- Both fixes address well-documented production crashes with clear root causes. The implementation is clean, follows existing patterns (`ctx.teamId || undefined` matches usage in other files), and includes comprehensive unit tests for the error traversal logic. The changes are minimal and focused on the specific bugs.
- No files require special attention
<sub>Last reviewed commit: c08e01b</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#21754: slack: pass inbound team_id into stream routing and startStream
by AIflow-Labs · 2026-02-20
86.3%
#20623: fix(slack): duplicate replies and missing streaming recipient params
by rahulsub-be · 2026-02-19
85.2%
#21218: fix(slack): pass recipient_team_id and recipient_user_id to chat stre…
by apham0001 · 2026-02-19
84.3%
#19083: Slack: preserve per-thread context and consistent thread replies
by jkimbo · 2026-02-17
80.2%
#22896: Handle Slack SDK .original in transient network detection
by creditblake · 2026-02-21
80.1%
#8024: fix(slack): resolve channel names via directory for cross-account m...
by emma-digital-assistant · 2026-02-03
79.6%
#23787: Handle transient Slack request errors without crashing the gateway
by graysurf · 2026-02-22
78.9%
#20244: resolution in DM with replyToMode=all
by saurav470 · 2026-02-18
78.7%
#17879: fix: prevent Slack auth errors from crashing the entire gateway
by zuyan9 · 2026-02-16
78.7%
#8684: fix(slack): add title param and channel resolution for file upload
by shuans · 2026-02-04
78.3%