Error Handling
Every failure is an error you can catch broadly or match by category.
- Node.js
- Go
- Rust
import { VideoSDKError, RoomNotFoundError } from "@videosdk.live/server-sdk";
try {
await client.rooms.get("does-not-exist");
} catch (err) {
if (err instanceof RoomNotFoundError) {
// room doesn't exist
} else if (err instanceof VideoSDKError) {
console.error(err.httpStatus, err.code, err.message, err.requestId);
}
}
_, err := client.Rooms.Get(ctx, "does-not-exist")
switch {
case videosdk.IsNotFound(err):
// room doesn't exist
case videosdk.IsRateLimit(err):
// back off
}
var apiErr *videosdk.Error
if errors.As(err, &apiErr) {
log.Println(apiErr.HTTPStatus, apiErr.Code, apiErr.Message, apiErr.RequestID)
}
match client.rooms().get("does-not-exist").await {
Ok(_room) => {}
Err(err) if err.is_not_found() => {
// room doesn't exist
}
Err(err) if err.is_rate_limit() => {
// back off
}
Err(err) => {
eprintln!("{:?} {:?} {err} {:?}", err.status(), err.code(), err.request_id());
}
}
The error object
Every error carries these fields:
| Field | Type | Description |
|---|---|---|
message | string | Human-readable error message. |
code | string | Machine-readable error code. |
httpStatus | number | HTTP status. Zero or absent when the error is not from a response (a network failure, timeout, or misconfiguration). |
requestId | string | Id of the failing request, useful for support. |
details | object | Raw error response body. |
method | string | HTTP method of the failing request. |
path | string | Path of the failing request. |
Error categories
Each category maps to an HTTP status. Node.js exposes an error subclass, Go exposes an Is* helper (and an Err* sentinel for errors.Is), and Rust exposes an is_* predicate on Error.
| Condition | HTTP | Node.js | Go | Rust |
|---|---|---|---|---|
| Bad request | 400 | ValidationError | IsValidation | is_validation() |
| Unauthorized | 401 | AuthenticationError | IsAuthentication | is_authentication() |
| Forbidden | 403 | PermissionError | IsPermission | is_permission() |
| Not found | 404 / 402 | RoomNotFoundError | IsNotFound | is_not_found() |
| Conflict | 409 | ResourceConflictError | IsConflict | is_conflict() |
| Rate limited | 429 | RateLimitError | IsRateLimit | is_rate_limit() |
| Timeout | TimeoutError | IsTimeout | is_timeout() | |
| Bad configuration | ConfigurationError | ErrConfiguration | Error::Configuration | |
| Webhook verification | WebhookVerificationError | ErrWebhookVerification | — |
In Go, configuration and webhook errors have no Is* helper — match them with errors.Is(err, videosdk.ErrConfiguration). In Rust, match the Error::Configuration variant directly; webhook verification is not yet available in the Rust SDK.
Retries
Transient failures are retried with exponential backoff (2 retries by default). The policy is conservative to avoid duplicating side effects:
429is retried for any request.- Network errors, timeouts, and
5xxare retried only for idempotent methods (GET,PUT,DELETE). APOSTorPATCHmay already have taken effect, so it is not retried.
Timeouts
Each request is bounded (default 30 seconds). Exceeding it raises a timeout error.
- Node.js
- Go
- Rust
const client = new VideoSDK({ apiKey, secret, timeoutMs: 60_000 });
client, err := videosdk.NewClient(
videosdk.WithAPIKey(apiKey),
videosdk.WithSecret(secret),
videosdk.WithRequestTimeout(60*time.Second),
)
let client = Client::builder()
.api_key(api_key)
.secret(secret)
.request_timeout(Duration::from_secs(60))
.build()?;
Got a Question? Ask us on discord

