Handle rate limits, unsupported features, and other errors from adapters.
The SDK provides typed error classes for common failure scenarios. All errors are importable from the chat package.
import { ChatError, RateLimitError, NotImplementedError, LockError } from "chat";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 |
RateLimitError
Thrown when a platform API returns a 429 response. The retryAfterMs property tells you how long to wait before retrying.
import { RateLimitError } from "chat";
try {
await thread.post("Hello!");
} catch (error) {
if (error instanceof RateLimitError) {
console.log(`Rate limited, retry after ${error.retryAfterMs}ms`);
}
}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.
import { NotImplementedError } from "chat";
try {
await thread.addReaction(emoji.thumbs_up);
} catch (error) {
if (error instanceof NotImplementedError) {
console.log(`Feature not supported: ${error.feature}`);
}
}See the feature matrix 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 option — set it to 'force' to release the existing lock instead of throwing.
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 |
Use instanceof to handle specific error types:
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;
}
}
});











