Skip to content

Error Handling

All errors thrown by Theatrical extend TheatricalError, which extends the native Error class. This means you can catch them with a standard try/catch and narrow to specific types with instanceof.

Error hierarchy

TheatricalError
├── AuthenticationError — 401 / invalid token
├── NotFoundError — 404 / resource doesn't exist
│ └── .resourceId — the ID that failed to resolve
├── ValidationError — 400 / request failed validation
│ └── .fields — { fieldName: message } map
├── RateLimitError — 429 / request throttled
│ └── .retryAfter — seconds to wait before retrying
└── ServerError — 5xx / upstream API error

Catching specific errors

import {
TheatricalClient,
AuthenticationError,
NotFoundError,
RateLimitError,
ValidationError,
} from '@theatrical/sdk';
try {
const session = await client.sessions.get('ses-unknown');
} catch (err) {
if (err instanceof NotFoundError) {
console.error(`Session not found: ${err.resourceId}`);
} else if (err instanceof RateLimitError) {
const waitMs = err.retryAfter * 1000;
await new Promise(r => setTimeout(r, waitMs));
// retry...
} else if (err instanceof ValidationError) {
for (const [field, message] of Object.entries(err.fields)) {
console.error(`${field}: ${message}`);
}
} else {
throw err; // re-throw unexpected errors
}
}

Automatic retry

The SDK automatically retries 5xx server errors and 429 rate limit responses using exponential backoff with full jitter. The retry budget is configured on the client:

const client = TheatricalClient.create({
apiKey: process.env.THEATRICAL_API_KEY!,
maxRetries: 3, // default
});

Set maxRetries: 0 to disable automatic retry entirely.