IMessageError or one of its subclasses. First branch by error class with instanceof, then use error.code for the exact reason.
Do not parse error.message for program logic. message is useful for logs and user-facing text. Use error.code, error.retryable, and error.context for decisions.
What You Can Do
| Need | Use |
|---|---|
| Distinguish auth, not-found, rate-limit, validation, and connection errors | error instanceof ... |
| Check the exact reason | error.code |
| Decide whether the same request is worth retrying | error.retryable |
| Read structured server context | error.context |
| Prevent duplicate writes from retried jobs | clientMessageId |
Handle Errors
Check the most specific subclasses first, and handleIMessageError last. If the error is not from the SDK, rethrow it.
| Error class | Usually means | Common handling |
|---|---|---|
AuthenticationError | Token rejected, expired, or unauthorized | Refresh credentials or stop sending |
NotFoundError | Chat, message, attachment, poll, address, or icon does not exist | Refresh local state and stop using the stale GUID |
RateLimitError | Server quota or rate limit rejected the request | Retry later if retryable and your business queue allows it |
ValidationError | Invalid input or failed precondition | Fix the input; do not retry unchanged |
ConnectionError | Network failure, timeout, or server unavailable | Retry according to your retry policy |
IMessageError | Other SDK error | Log code, grpcCode, and context; use your fallback path |
Error Object
All SDK errors include these fields:| Field | How to use it |
|---|---|
code | Program branches and exact error handling |
retryable | Decide whether the same request can be retried |
grpcCode | Debug low-level transport state |
context | See which field, GUID, or resource caused the failure |
message | Logs or user-facing copy |
cause | Original lower-level error when the SDK wraps one; may be absent |
Common Error Codes
ErrorCode is both a runtime object and a TypeScript type. In most code, check the specific error class first, then compare error.code:
| Category | Error codes |
|---|---|
| Authentication | unauthenticated, tokenExpired, tokenBlocked, unauthorized |
| Rate limits | dailyLimitExceeded, recipientLimitExceeded, uploadRateExceeded, contentDuplicateExceeded, recipientCoolingDown, recipientLocked, sendReceiveRatioExceeded |
| Duplicate writes | duplicateMessage |
| Not found | chatNotFound, messageNotFound, attachmentNotFound, addressNotFound, sharedFriendLocationNotFound, groupIconNotFound, pollNotFound |
| Validation | invalidArgument, preconditionFailed, operationNotSupported, attachmentNotReady, privateApiUnavailable |
| Infrastructure | serviceUnavailable, timeout, internalError, databaseError, networkError |
gRPC Status Mapping
Most application code should not branch ongrpcCode. Prefer error classes and error.code. Use this table when debugging transport-level behavior.
| gRPC status | SDK error class |
|---|---|
UNAUTHENTICATED, PERMISSION_DENIED | AuthenticationError |
NOT_FOUND | NotFoundError |
RESOURCE_EXHAUSTED | RateLimitError |
INVALID_ARGUMENT, FAILED_PRECONDITION | ValidationError |
UNAVAILABLE, DEADLINE_EXCEEDED | ConnectionError |
| Everything else | IMessageError |
Retries
Setretry when creating the client. The SDK retries retryable unary requests automatically. Invalid input, missing resources, and permission failures do not become valid by retrying the same request.
RetryOptions:
| Option | Meaning |
|---|---|
retry: true | Use the SDK default retry policy |
maxAttempts | Maximum attempts, including the first request |
initialDelay | Delay before the first retry, in milliseconds |
maxDelay | Maximum delay between retries, in milliseconds |
| Case | Automatically retried |
|---|---|
Unary request with error.retryable === true | Yes |
ValidationError or invalid input | No |
| Live streams, download streams, location streams | No |
Idempotency
Most calls do not needclientMessageId. Use it only when your queue or worker may rerun the same logical write after a crash or timeout. Automatic retry handles the same SDK call. clientMessageId handles your business job starting the same write again.
Use the same clientMessageId every time you retry the same logical write:
| Case | Result |
|---|---|
Same clientMessageId + same write | Server treats it as a duplicate and returns the original result |
New clientMessageId | Server treats it as a new independent write |
Next Steps
- Events — recover after stream disconnects
- Messages — understand write methods, idempotency keys, and message errors
- Attachments — handle
attachmentNotReady