UNPKG

chat

Version:

Unified chat abstraction for Slack, Teams, Google Chat, and Discord

160 lines (131 loc) 5.25 kB
--- title: Error Handling description: Handle rate limits, unsupported features, and other errors from adapters. type: guide prerequisites: - /docs/usage --- The SDK provides typed error classes for common failure scenarios. All errors are importable from the `chat` package. ```typescript import { ChatError, RateLimitError, NotImplementedError, LockError } from "chat"; ``` ## Error types ### ChatError Base error class for all SDK errors. Every error below extends `ChatError`. The `code` property carries a machine-readable identifier you can branch on: | Code | Thrown by | Meaning | |------|-----------|---------| | `NOT_SUPPORTED` | `bot.openDM`, `bot.getUser` | The resolved adapter doesn't implement this method | | `INVALID_THREAD_ID` | `bot.thread`, internal routing | Thread ID does not match the `adapter:channel:thread` shape | | `INVALID_CHANNEL_ID` | `bot.channel` | Channel ID does not match the `adapter:channel` shape | | `ADAPTER_NOT_FOUND` | `bot.thread`, `bot.channel` | Thread/channel ID references an adapter that wasn't registered on this `Chat` instance | | `AMBIGUOUS_USER_ID` | `bot.getUser`, `bot.openDM` | Numeric user ID could match more than one registered adapter (Discord/Telegram/GitHub) | | `UNKNOWN_USER_ID_FORMAT` | `bot.getUser`, `bot.openDM` | The `userId` doesn't match any platform's known ID format | | `RATE_LIMITED` | Any platform call | Platform returned 429; see `RateLimitError` below | | `NOT_IMPLEMENTED` | Any platform call | The adapter doesn't implement this feature; see `NotImplementedError` below | | `LOCK_FAILED` | Inbound message routing | Distributed lock was busy; see `LockError` below | <TypeTable type={{ message: { description: 'Human-readable error message.', type: 'string', }, code: { description: 'Machine-readable error code (see table above).', type: 'string', }, cause: { description: 'Original error that caused this one.', type: 'unknown | undefined', }, }} /> ### RateLimitError Thrown when a platform API returns a 429 response. The `retryAfterMs` property tells you how long to wait before retrying. ```typescript title="lib/bot.ts" lineNumbers import { RateLimitError } from "chat"; try { await thread.post("Hello!"); } catch (error) { if (error instanceof RateLimitError) { console.log(`Rate limited, retry after ${error.retryAfterMs}ms`); } } ``` <TypeTable type={{ code: { description: 'Always "RATE_LIMITED".', type: 'string', }, retryAfterMs: { description: 'Milliseconds to wait before retrying.', type: 'number | undefined', }, }} /> ### NotImplementedError Thrown when you call a feature that a platform doesn't support. For example, calling `addReaction()` on Teams or `schedule()` on adapters without native scheduling support. ```typescript title="lib/bot.ts" lineNumbers import { NotImplementedError } from "chat"; try { await thread.addReaction(emoji.thumbs_up); } catch (error) { if (error instanceof NotImplementedError) { console.log(`Feature not supported: ${error.feature}`); } } ``` <TypeTable type={{ code: { description: 'Always "NOT_IMPLEMENTED".', type: 'string', }, feature: { description: 'Name of the unsupported feature.', type: 'string | undefined', }, }} /> See the [feature matrix](/docs/adapters) for which features are supported on each platform. ### LockError Thrown when the SDK fails to acquire a distributed lock on a thread (used to prevent concurrent processing of messages in the same thread). You can control this behavior with the [`onLockConflict`](/docs/usage#configuration-options) option — set it to `'force'` to release the existing lock instead of throwing. <TypeTable type={{ code: { description: 'Always "LOCK_FAILED".', type: 'string', }, }} /> ## Adapter errors Adapters also throw specialized errors from the `@chat-adapter/shared` package: | Error | Code | Description | |-------|------|-------------| | `AdapterRateLimitError` | `RATE_LIMITED` | Platform rate limit hit, includes `retryAfter` in seconds | | `AuthenticationError` | `AUTH_FAILED` | Invalid or expired credentials | | `ResourceNotFoundError` | `NOT_FOUND` | Requested resource (channel, message) doesn't exist | | `PermissionError` | `PERMISSION_DENIED` | Bot lacks required permissions/scopes | | `ValidationError` | `VALIDATION_ERROR` | Invalid input data (e.g. message too long) | | `NetworkError` | `NETWORK_ERROR` | Connectivity issue with platform API | ## Catching errors Use `instanceof` to handle specific error types: ```typescript title="lib/bot.ts" lineNumbers import { RateLimitError, NotImplementedError } from "chat"; bot.onNewMention(async (thread, message) => { try { await thread.post("Processing..."); await thread.addReaction(emoji.eyes); } catch (error) { if (error instanceof RateLimitError) { // Wait and retry await new Promise((r) => setTimeout(r, error.retryAfterMs ?? 5000)); await thread.post("Processing..."); } else if (error instanceof NotImplementedError) { // Skip unsupported features gracefully } else { throw error; } } }); ```