#17558: fix(slack): replace files.uploadV2 with 3-step upload flow to fix missing_scope error
channel: slack
size: S
Cluster:
Slack Integration Improvements
## Problem
`uploadSlackFile()` uses `client.files.uploadV2()` from `@slack/web-api`, which internally calls the **deprecated `files.upload`** endpoint. This fails with `missing_scope` even when `files:write` is correctly granted in the bot token scopes.
The direct REST API (`files.getUploadURLExternal` → upload → `files.completeUploadExternal`) works fine with the same token, confirming the scope is present but the SDK method uses a different code path.
## Fix
Replace the single `files.uploadV2()` call with Slack's recommended 3-step upload flow:
1. `files.getUploadURLExternal` — get presigned upload URL + file_id
2. `fetch(upload_url)` — upload file content to presigned URL
3. `files.completeUploadExternal` — finalize & share to channel/thread
## Changes
- **1 file changed**: `src/slack/send.ts`
- Only the `uploadSlackFile()` function body is modified
- Function signature unchanged
- All existing behavior preserved (channel uploads, thread replies via `thread_ts`, captions via `initial_comment`)
- Removed unused `FilesUploadV2Arguments` type import
## Testing
Manually verified the 3-step flow works correctly:
- ✅ Channel upload (file shared to channel with caption)
- ✅ Thread reply upload (file shared in thread with `thread_ts`)
- ✅ Same bot token, same `files:write` scope — no more `missing_scope` error
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR replaces the broken `files.uploadV2()` SDK call in `uploadSlackFile()` with Slack's recommended 3-step upload flow: `getUploadURLExternal` → presigned URL POST → `completeUploadExternal`. The change fixes `missing_scope` errors that occurred because `files.uploadV2` internally uses the deprecated `files.upload` endpoint.
- The implementation is clean and well-structured with explicit error handling at each step
- Function signature and all existing behavior (channel uploads, thread replies via `thread_ts`, captions via `initial_comment`) are preserved
- The return value semantics remain the same — both old and new code return a Slack file ID, not a message timestamp. This is a pre-existing limitation where `messageId` in `SlackSendResult` won't be a valid Slack `ts` for file-only uploads (affecting downstream operations like reactions/edits), but this PR does not change that behavior
- The unused `FilesUploadV2Arguments` import is correctly removed
- CHANGELOG entry is accurate
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge — it fixes a real Slack API compatibility issue with a well-structured replacement that preserves all existing behavior.
- Score of 4 reflects that this is a focused, well-implemented fix for a known Slack SDK issue. The 3-step upload flow follows Slack's recommended approach, error handling is thorough, and existing behavior is preserved. Minor deduction because the Content-Type header is not forwarded to the presigned URL upload (style concern, not a functional bug).
- No files require special attention. The change is isolated to the `uploadSlackFile` function body in `src/slack/send.ts`.
<sub>Last reviewed commit: 30ee226</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#8684: fix(slack): add title param and channel resolution for file upload
by shuans · 2026-02-04
85.6%
#20479: fix(slack): keep replies flowing for oversized file uploads
by olyashok · 2026-02-19
82.8%
#18763: fix(slack): add auth header when downloading forwarded attachment i...
by amabito · 2026-02-17
78.2%
#19430: Slack: infer bare user targets before media upload
by gg2uah · 2026-02-17
77.7%
#14847: fix(slack): preserve auth across Slack-hosted file redirects
by natashache · 2026-02-12
77.3%
#8024: fix(slack): resolve channel names via directory for cross-account m...
by emma-digital-assistant · 2026-02-03
77.3%
#20406: fix(slack): respect replyToMode when computing statusThreadTs in DMs
by QuinnYates · 2026-02-18
76.8%
#9166: Fix: Use userToken for Slack file downloads
by vishaltandale00 · 2026-02-04
76.6%
#22096: fix(slack): traverse .original for Slack SDK errors; pass recipient...
by maiclaw · 2026-02-20
76.3%
#15095: fix(slack): process all file attachments instead of only the first
by Lar000ki · 2026-02-13
76.1%