Profiles·Public

@slack/web-api

semver>=6.0.0 <8.0.0postconditions22functions22last verified2026-06-23coverage score100%

Postconditions: what we check

  • chat.postMessage · chat-postmessage-no-trycatch
    error
    Whenchat.postMessage() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 unavailablevisibilityvisible
    Sources[1]
  • users.list · users-list-no-trycatch
    error
    Whenusers.list() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required handlingMUST wrap await client.users.list() in try-catch block to handle network errors, rate limiting, and HTTP errors.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • users.info · users-info-no-trycatch
    error
    Whenusers.info() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required handlingMUST wrap await client.users.info() in try-catch block.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[2]
  • conversations.list · conversations-list-no-trycatch
    error
    Whenconversations.list() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required handlingMUST wrap await client.conversations.list() in try-catch block.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[3]
  • conversations.join · conversations-join-no-trycatch
    error
    Whenconversations.join() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required handlingMUST wrap await client.conversations.join() in try-catch block.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4]
  • conversations.invite · conversations-invite-no-trycatch
    error
    Whenconversations.invite() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required handlingMUST wrap await client.conversations.invite() in try-catch block.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5]
  • files.upload · files-upload-no-trycatch
    error
    Whenfiles.upload() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required handlingMUST wrap await client.files.upload() in try-catch block.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6]
  • auth.test · auth-test-no-trycatch
    error
    Whenauth.test() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required handlingMUST wrap await client.auth.test() in try-catch block.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[7]
  • chat.update · chat-update-no-trycatch
    error
    Whenchat.update() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 unavailablevisibilityvisible
    Sources[8]
  • chat.postEphemeral · chat-postephemeral-no-trycatch
    error
    Whenchat.postEphemeral() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 unavailablevisibilityvisible
    Sources[9]
  • chat.delete · chat-delete-no-trycatch
    error
    Whenchat.delete() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 unavailablevisibilityvisible
    Sources[10]
  • chat.scheduleMessage · chat-schedulemessage-no-trycatch
    error
    Whenchat.scheduleMessage() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 performancevisibilitysilent
    Sources[11]
  • conversations.create · conversations-create-no-trycatch
    error
    Whenconversations.create() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 unavailablevisibilityvisible
    Sources[12]
  • conversations.history · conversations-history-no-trycatch
    error
    Whenconversations.history() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 unavailablevisibilityvisible
    Sources[13]
  • conversations.open · conversations-open-no-trycatch
    error
    Whenconversations.open() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 performancevisibilitysilent
    Sources[14]
  • views.open · views-open-no-trycatch
    error
    Whenviews.open() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 unavailablevisibilityvisible
    Sources[15]
  • reactions.add · reactions-add-no-trycatch
    error
    Whenreactions.add() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 unavailablevisibilityvisible
    Sources[16]
  • filesUploadV2 · filesuploadv2-no-trycatch
    error
    WhenfilesUploadV2() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 performancevisibilitysilent
    Sources[17]
  • users.lookupByEmail · users-lookupbyemail-no-trycatch
    error
    Whenusers.lookupByEmail() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 unavailablevisibilityvisible
    Sources[18]
  • chat.startStream · chat-startstream-no-trycatch
    error
    Whenchat.startStream() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 performancevisibilitysilent
    Sources[19]
  • chat.appendStream · chat-appendstream-no-trycatch
    error
    Whenchat.appendStream() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 performancevisibilitysilent
    Sources[20]
  • chat.stopStream · chat-stopstream-no-trycatch
    error
    Whenchat.stopStream() called without try-catch or .catch() handler
    ThrowsWebAPIPlatformError or WebAPIRateLimitedError
    Required 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 performancevisibilitysilent
    Sources[21]

Sources

Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.

Official documentation

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

  1. Web API Overview

  2. Error Handling Documentation

  3. Rate Limits

  4. Security Best Practices

API Method Documentation

  1. chat.postMessage

  2. users.list

  3. users.info

  4. conversations.* methods

  5. files.upload

  6. auth.test

Security Research

  1. Token Leakage Remediation

  2. Common Slack API Errors

Troubleshooting Resources

  1. channel_not_found Troubleshooting

Real-World Usage Analysis

Repos Examined

  1. 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
  2. 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
  3. 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

Error Types and HTTP Status Codes

Error Types (from @slack/web-api)

  1. RequestError

    • Trigger: Network connection failures, api.slack.com unreachable
    • Properties: error.original contains underlying error
    • Handling: Retry with backoff or fail gracefully
  2. RateLimitedError

    • Trigger: HTTP 429 (Too Many Requests)
    • Properties: error.retryAfter (seconds to wait)
    • Handling: Wait retryAfter seconds before retry (automatic in WebClient)
  3. 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-After header)
  • 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:

Note: This does not include transitive dependencies. Regular security scanning recommended.


Contract Design Rationale

Covered Methods

We selected 8 core methods based on:

  1. Usage frequency: Most commonly used in real-world codebases
  2. Error-prone: High likelihood of missing error handling
  3. Impact: Failure modes affect core functionality

Methods:

  • chat.postMessage() - Most common, high impact
  • users.list(), users.info() - User management operations
  • conversations.list(), conversations.join(), conversations.invite() - Channel operations
  • files.upload() - File operations
  • auth.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.ok field

    • 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

  1. proper-error-handling.ts: Demonstrates correct patterns

    • Try-catch around all async calls
    • Checks response.ok field
    • Handles rate limiting with retryAfter
    • Expected: 0 violations
  2. missing-error-handling.ts: Demonstrates violations

    • No try-catch on async calls
    • Does not check response.ok
    • Expected: Multiple ERROR violations
  3. 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

  1. Additional Methods: Add coverage for chat.update(), chat.delete(), reactions.*
  2. Response Validation: Detect missing pagination handling for list methods
  3. Scope Validation: Check if token has required OAuth scopes before call
  4. Token Leakage: Detect if tokens are logged or echoed in errors
  5. 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
Need a different package?
Request a profile