@slack/web-api
>=6.0.0 <8.0.0postconditions22functions22last verified2026-06-23coverage score100%Postconditions: what we check
- chat.postMessage · chat-postmessage-no-trycatcherrorWhenchat.postMessage() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.chat.postMessage() in try-catch block. Catch block should handle RequestError (network failures), RateLimitedError (check retryAfter property), and HTTPError. Also check response.ok === false for API-level errors (invalid_auth, channel_not_found, rate_limited).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - users.list · users-list-no-trycatcherrorWhenusers.list() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.users.list() in try-catch block to handle network errors, rate limiting, and HTTP errors.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - users.info · users-info-no-trycatcherrorWhenusers.info() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.users.info() in try-catch block.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - conversations.list · conversations-list-no-trycatcherrorWhenconversations.list() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.conversations.list() in try-catch block.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3] - conversations.join · conversations-join-no-trycatcherrorWhenconversations.join() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.conversations.join() in try-catch block.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[4] - conversations.invite · conversations-invite-no-trycatcherrorWhenconversations.invite() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.conversations.invite() in try-catch block.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[5] - files.upload · files-upload-no-trycatcherrorWhenfiles.upload() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.files.upload() in try-catch block.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[6] - auth.test · auth-test-no-trycatcherrorWhenauth.test() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.auth.test() in try-catch block.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[7] - chat.update · chat-update-no-trycatcherrorWhenchat.update() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.chat.update() in try-catch. Handle message_not_found (skip or log — message was deleted), cant_update_message (log — bot didn't post original), edit_window_closed (log — past edit window), and RateLimitedError (wait retryAfter seconds).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[8] - chat.postEphemeral · chat-postephemeral-no-trycatcherrorWhenchat.postEphemeral() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.chat.postEphemeral() in try-catch. Handle user_not_in_channel (user left — log and skip), channel_not_found (invalid channel — log), and RateLimitedError (retry after delay).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[9] - chat.delete · chat-delete-no-trycatcherrorWhenchat.delete() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.chat.delete() in try-catch. Treat message_not_found as a safe no-op (already deleted). Handle cant_delete_message with a log (wrong bot identity). Handle RateLimitedError with retry-after backoff.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10] - chat.scheduleMessage · chat-schedulemessage-no-trycatcherrorWhenchat.scheduleMessage() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.chat.scheduleMessage() in try-catch. Handle time_in_past (revalidate scheduling logic, notify user), time_too_far (cap at 120 days), channel_not_found (validate channel before scheduling), and RateLimitedError (retry after delay).costlowin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[11] - conversations.create · conversations-create-no-trycatcherrorWhenconversations.create() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.conversations.create() in try-catch. Handle name_taken (append suffix or look up existing), invalid_name (sanitize name before calling), restricted_action (check workspace settings, surface to admin), and RateLimitedError (exponential backoff).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[12] - conversations.history · conversations-history-no-trycatcherrorWhenconversations.history() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.conversations.history() in try-catch. Handle not_in_channel (bot was removed — stop polling), channel_not_found (channel gone — remove from watch list), invalid_cursor (restart pagination from beginning), and RateLimitedError (wait retryAfter seconds before continuing pagination).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[13] - conversations.open · conversations-open-no-trycatcherrorWhenconversations.open() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.conversations.open() in try-catch. Handle user_disabled (mark user as inactive, stop sending notifications), user_not_found (validate user ID before calling), too_many_users (reduce group size to ≤8), and RateLimitedError (retry after delay).costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[14] - views.open · views-open-no-trycatcherrorWhenviews.open() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.views.open() in try-catch. Handle expired_trigger_id (send ephemeral fallback message to user), invalid_trigger_id/exchanged_trigger_id (log and skip — already handled), view_too_large (reduce block count), and RateLimitedError (retry after delay). IMPORTANT: call views.open immediately after receiving the trigger_id — no async work between receiving the payload and calling views.open.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[15] - reactions.add · reactions-add-no-trycatcherrorWhenreactions.add() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.reactions.add() in try-catch. Treat already_reacted as safe no-op (idempotent — reaction already present). Handle message_not_found (message was deleted — skip), too_many_emoji (workspace limit reached — log), and RateLimitedError (retry with backoff).costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[16] - filesUploadV2 · filesuploadv2-no-trycatcherrorWhenfilesUploadV2() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.filesUploadV2() in try-catch. Handle file_upload_size_restricted (notify user of size limit), file_uploads_disabled (surface admin restriction to user), storage_limit_reached (notify workspace admin), FileUploadInvalidArgumentsError (fix argument validation — always provide filename), and RateLimitedError (retry after delay).costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[17] - users.lookupByEmail · users-lookupbyemail-no-trycatcherrorWhenusers.lookupByEmail() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.users.lookupByEmail() in try-catch. Handle users_not_found as an expected outcome (not all emails map to workspace users — fall back to email notification instead of DM). Handle missing_scope by checking OAuth scope includes users:read.email during app authorization. Handle RateLimitedError with retry backoff.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[18] - chat.startStream · chat-startstream-no-trycatcherrorWhenchat.startStream() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.chat.startStream() in try-catch. Handle channel_not_found / is_archived (fall back to chat.postMessage in a different channel or surface to user), messages_tab_disabled (instruct user to enable Messages tab), messaging_processing_failed (retry with backoff — transient), invalid_blocks (validate Block Kit before sending), missing_scope (surface OAuth scope gap to admin), and RateLimitedError (wait retryAfter seconds). Never start a stream without a corresponding chat.stopStream call — leaving a stream open locks the message in "streaming" state.costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[19] - chat.appendStream · chat-appendstream-no-trycatcherrorWhenchat.appendStream() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.chat.appendStream() in try-catch. Handle stopped_by_user as a clean exit signal (break out of the token loop, do NOT call stopStream again — message is already terminal). Handle message_not_in_streaming_state as terminal (LLM response continues to a new message if needed). Handle message_not_found by aborting the loop. Handle invalid_chunks by logging the offending chunk and continuing (or aborting on repeated failures). Handle RateLimitedError with delay (Slack throttles streaming on a separate bucket — buffer chunks before retry). On any unhandled error, call chat.stopStream to release the streaming lock.costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[20] - chat.stopStream · chat-stopstream-no-trycatcherrorWhenchat.stopStream() called without try-catch or .catch() handlerThrows
WebAPIPlatformError or WebAPIRateLimitedErrorRequired handlingMUST wrap await client.chat.stopStream() in try-catch. Treat message_not_in_streaming_state as a safe no-op (idempotent — message is already terminal). Treat message_not_found as a safe no-op (already deleted). Handle attachment_payload_limit_exceeded / too_many_attachments by trimming the final payload and retrying without the concluding attachments. Handle RateLimitedError with retry (this is the LAST chance to terminate the stream — failing to retry leaves a hung "streaming" message). On unrecoverable errors, log loudly so operations can clear the orphaned stream state.costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[21]
Sources
Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.
- [1]tessl.io/registry/tessl/npm-slack--web-apiError Handling
- [2]api.slack.com/methods/users.infoUsers.Info
- [3]api.slack.com/methods/conversations.listConversations.List
- [4]api.slack.com/methods/conversations.joinConversations.Join
- [5]api.slack.com/methods/conversations.inviteConversations.Invite
- [6]api.slack.com/methods/files.uploadFiles.Upload
- [7]api.slack.com/methods/auth.testAuth.Test
- [8]docs.slack.dev/reference/methods/chat.updateChat.Update
- [9]docs.slack.dev/reference/methods/chat.postEphemeralChat.PostEphemeral
- [10]docs.slack.dev/reference/methods/chat.deleteChat.Delete
- [11]docs.slack.dev/reference/methods/chat.scheduleMessageChat.ScheduleMessage
- [12]docs.slack.dev/reference/methods/conversations.createConversations.Create
- [13]docs.slack.dev/reference/methods/conversations.historyConversations.History
- [14]docs.slack.dev/reference/methods/conversations.openConversations.Open
- [15]docs.slack.dev/reference/methods/views.openViews.Open
- [16]docs.slack.dev/reference/methods/reactions.addReactions.Add
- [17]docs.slack.dev/reference/methods/files.getUploadURLExternalFiles.GetUploadURLExternal
- [18]docs.slack.dev/reference/methods/users.lookupByEmailUsers.LookupByEmail
- [19]docs.slack.dev/reference/methods/chat.startStreamChat.StartStream
- [20]docs.slack.dev/reference/methods/chat.appendStreamChat.AppendStream
- [21]docs.slack.dev/reference/methods/chat.stopStreamChat.StopStream
Research notes
Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.
Sources for @slack/web-api Nark profile
Package: @slack/web-api Version: 7.x (latest as of 2026-02-25) Contract Version: 1.0.0 Research Date: 2026-02-25
Overview
The @slack/web-api package is the official Slack Web API client for Node.js. It provides a convenient interface for calling Slack Web API methods, with built-in retry logic, rate limit handling, and error typing.
Key Behavioral Characteristics:
- All API methods are async and return
Promise<WebAPICallResult> - HTTP 200 is returned even for API-level errors (must check
response.ok) - Built-in retry logic: Up to 10 retries over ~30 minutes with exponential backoff
- Three main error types:
RequestError,RateLimitedError,HTTPError
Primary Sources
Official Slack Documentation
-
Web API Overview
- URL: https://docs.slack.dev/tools/node-slack-sdk/web-api/
- Content: Main documentation for the Node.js SDK
- Used for: Understanding API structure and usage patterns
-
Error Handling Documentation
- URL: https://tessl.io/registry/tessl/npm-slack--web-api/7.10.0/files/docs/error-handling.md
- Content: Detailed error types and handling patterns
- Used for: Error type definitions, retry behavior, error handling best practices
-
Rate Limits
- URL: https://docs.slack.dev/apis/web-api/rate-limits/
- URL: https://medium.com/slack-developer-blog/handling-rate-limits-with-slacks-apis-f6f8a63bdbdc
- Content: Rate limiting behavior, 429 responses, Retry-After headers
- Used for: Understanding rate limit errors and mitigation strategies
-
Security Best Practices
- URL: https://docs.slack.dev/security/
- URL: https://api.slack.com/authentication/best-practices
- Content: Token security, secret management, error handling security
- Used for: Token leakage prevention recommendations
API Method Documentation
-
chat.postMessage
- URL: https://docs.slack.dev/reference/methods/chat.postMessage/
- URL: https://api.slack.com/methods/chat.postMessage
- Content: Method signature, error codes, required scopes
- Used for: Preconditions, error scenarios, permission requirements
-
users.list
- URL: https://api.slack.com/methods/users.list
- Content: Method signature, required scopes, error codes
- Used for: Permission requirements, error scenarios
-
users.info
- URL: https://api.slack.com/methods/users.info
- Content: Method signature, error codes
- Used for: Error scenarios, validation requirements
-
conversations.* methods
- URL: https://api.slack.com/methods/conversations.list
- URL: https://api.slack.com/methods/conversations.join
- URL: https://api.slack.com/methods/conversations.invite
- Content: Method signatures, error codes, permission requirements
- Used for: Channel operation error scenarios
-
files.upload
- URL: https://api.slack.com/methods/files.upload
- Content: Method signature, file size limits, error codes
- Used for: File upload constraints and error scenarios
-
auth.test
- URL: https://api.slack.com/methods/auth.test
- Content: Token validation method
- Used for: Authentication validation patterns
Security Research
-
Token Leakage Remediation
- URL: https://www.gitguardian.com/remediation/slack-app-api-token
- Content: Risks and remediation for leaked Slack tokens
- Used for: Security considerations in contract
-
Common Slack API Errors
- URL: https://github.com/slackapi/node-slack-sdk/issues/1646
- URL: https://github.com/beginner-corp/slack/issues/105
- Content: Real-world error handling issues and discussions
- Used for: Understanding common developer pitfalls
Troubleshooting Resources
- channel_not_found Troubleshooting
- URL: https://knock.app/blog/troubleshooting-channel-not-found-in-slack-incoming-webhooks
- Content: Common causes of channel_not_found errors
- Used for: Preconditions for channel-based operations
Real-World Usage Analysis
Repos Examined
-
trigger.dev (Multiple packages)
- File:
apps/webapp/app/services/slack.server.ts - Pattern: ✅ Proper error handling with try-catch
- File:
references/d3-chat/src/lib/slack.ts - Pattern: ❌ Missing error handling on chat.postMessage
- Observation: Inconsistent error handling across codebase
- File:
-
payload (GitHub Actions)
- File:
.github/actions/activity/src/new-issues.ts - Pattern: ✅ Proper error handling with try-catch
- Pattern: ✅ Token validation before use
- Observation: Good error handling practices
- File:
-
backstage (notifications plugin)
- File:
plugins/notifications-backend-module-slack/src/lib/SlackNotificationProcessor.ts - Pattern: 🌟 Advanced error handling with Promise.allSettled, throttling, metrics
- Pattern: ✅ Try-catch around channel lookup operations
- Observation: Production-grade error handling implementation
- File:
Error Types and HTTP Status Codes
Error Types (from @slack/web-api)
-
RequestError
- Trigger: Network connection failures, api.slack.com unreachable
- Properties:
error.originalcontains underlying error - Handling: Retry with backoff or fail gracefully
-
RateLimitedError
- Trigger: HTTP 429 (Too Many Requests)
- Properties:
error.retryAfter(seconds to wait) - Handling: Wait
retryAfterseconds before retry (automatic in WebClient)
-
HTTPError
- Trigger: Unexpected HTTP status codes
- Properties:
statusCode,statusMessage,headers,body - Handling: Log and investigate unexpected responses
HTTP Status Codes
- 200 OK: Success OR API-level error (check
response.ok) - 429 Too Many Requests: Rate limiting (check
Retry-Afterheader) - 401 Unauthorized: Invalid/expired/revoked token
- 403 Forbidden: Missing OAuth scope/permissions
API-Level Error Codes (in response body when ok: false)
- invalid_auth: Token is invalid, expired, or revoked
- token_revoked: Token has been explicitly revoked
- account_inactive: Slack account is inactive
- not_authed: No authentication token provided
- channel_not_found: Invalid channel ID or bot not a member
- user_not_found: Invalid user ID
- no_permission: Token lacks required OAuth scope
- rate_limited: Rate limit exceeded (alternative to HTTP 429)
- is_archived: Channel is archived
- file_too_large: File exceeds size limits
Built-in Retry Behavior
The WebClient includes automatic retry logic:
- Max Retries: 10 attempts
- Duration: Spaced over ~30 minutes
- Backoff: Exponential backoff algorithm
- Triggers: Automatically retries on:
- Rate limiting (429 / RateLimitedError)
- Server errors (5xx status codes)
- Configuration: Can be disabled or customized via
retryConfig
Source: https://tessl.io/registry/tessl/npm-slack--web-api/7.10.0/files/docs/error-handling.md
Security Considerations
Token Leakage
Risk: Slack tokens leaked in:
- Public GitHub repositories (hardcoded)
- Error messages/logs (echoed back)
- Non-secure storage
Impact:
- Unauthorized access to Slack workspace
- Data breaches of user data and messages
- Potential for malicious message posting
Mitigation:
- Store tokens in environment variables or secret managers
- Never hardcode tokens in source code
- Avoid echoing tokens in error messages
- Use generic error messages for users
Sources:
CVE Analysis
Status: No known CVEs for @slack/web-api package as of 2026-02-25
Checked:
- Snyk vulnerability database: https://security.snyk.io/package/npm/@slack%2Fweb-api
- npm audit: No Slack-related findings
- CVE Details: No direct vulnerabilities
Note: This does not include transitive dependencies. Regular security scanning recommended.
Contract Design Rationale
Covered Methods
We selected 8 core methods based on:
- Usage frequency: Most commonly used in real-world codebases
- Error-prone: High likelihood of missing error handling
- Impact: Failure modes affect core functionality
Methods:
chat.postMessage()- Most common, high impactusers.list(),users.info()- User management operationsconversations.list(),conversations.join(),conversations.invite()- Channel operationsfiles.upload()- File operationsauth.test()- Token validation
Severity Levels
-
ERROR: Missing try-catch on async API calls
- Rationale: Can crash application, violates async error handling principles
- Impact: Production incidents, uncaught promise rejections
-
WARNING: Not checking
response.okfield- Rationale: API returns 200 even for errors, must check response body
- Impact: Silent failures, incorrect assumptions about success
Not Covered
Why not chat.update(), chat.delete()?
- Less commonly used than
postMessage() - Same error patterns as covered methods
- Can be added in future contract versions
Why not Real-Time Messaging API?
- Different package (
@slack/rtm-api) - WebSocket-based, not HTTP-based
- Requires separate contract
Testing Strategy
Fixtures Created
-
proper-error-handling.ts: Demonstrates correct patterns
- Try-catch around all async calls
- Checks
response.okfield - Handles rate limiting with
retryAfter - Expected: 0 violations
-
missing-error-handling.ts: Demonstrates violations
- No try-catch on async calls
- Does not check
response.ok - Expected: Multiple ERROR violations
-
instance-usage.ts: Tests detection via instances
- WebClient instance stored in variable
- Methods called via instance
- Expected: Violations detected on instance methods
Real-World Validation
Repos to Test:
- trigger.dev (known to have both good and bad patterns)
- payload (known to have proper error handling)
- backstage (advanced error handling)
Expected Results:
- True Positives: Missing try-catch in trigger.dev/d3-chat
- True Negatives: Proper handling in payload, trigger.dev/webapp
Version History
Version 1.0.0 (2026-02-25)
- Initial contract covering 8 core methods
- ERROR severity for missing try-catch
- WARNING severity for not checking response.ok
- Based on @slack/web-api 7.x documentation
Future Enhancements
- Additional Methods: Add coverage for
chat.update(),chat.delete(),reactions.* - Response Validation: Detect missing pagination handling for list methods
- Scope Validation: Check if token has required OAuth scopes before call
- Token Leakage: Detect if tokens are logged or echoed in errors
- Rate Limit Prevention: Detect missing backoff strategies in high-volume scenarios
Contributors
- Claude Sonnet 4.5 (Initial research and contract design)
- Research Date: 2026-02-25
- Contract Version: 1.0.0