Error Handling
The SDK transforms all API errors into typed error classes with rich metadata. All errors extend SonarSDKError.
Error Class Hierarchy
SonarSDKError (base) βββ AuthenticationError (401/403) βββ RateLimitError (429) βββ DocumentNotFoundError (404) βββ ValidationError (400)Base Error β SonarSDKError
All SDK errors extend this base class.
| Property | Type | Description |
|---|---|---|
message | string | Human-readable error message |
code | ErrorCode | string | Machine-readable error code |
status | number? | HTTP status code |
requestId | string? | Unique request identifier for debugging |
details | Record<string, unknown>? | Additional error context |
errors | FieldError[]? | Array of field-level validation errors |
timestamp | string | ISO 8601 timestamp when the error was created |
Methods: toJSON() β Serializes the error to a plain object.
try { await sdk.documents.get('invalid_id');} catch (err) { if (err instanceof SonarSDKError) { console.log(err.code); // "DOCUMENT_NOT_FOUND" console.log(err.status); // 404 console.log(err.requestId); // "req_abc123" console.log(err.timestamp); // "2025-06-01T12:00:00.000Z" console.log(err.toJSON()); // serialized error object }}AuthenticationError
Thrown for authentication and authorization failures (HTTP 401/403).
Common Causes:
- Missing API key
- API key doesnβt start with
sk_ - Expired or revoked API key
- Insufficient permissions for the requested operation
import { AuthenticationError } from '@sonar/sdk';
try { const sdk = new SonarSDK({ apiKey: 'bad_key', instanceName: 'demo' });} catch (err) { if (err instanceof AuthenticationError) { console.log(err.message); // "API key must start with \"sk_\"" console.log(err.code); // "INVALID_API_KEY" }}RateLimitError
Thrown when the API rate limit is exceeded (HTTP 429).
| Property | Type | Description |
|---|---|---|
code | string | Always 'RATE_LIMIT_EXCEEDED' |
retryAfter | number? | Seconds to wait before retrying |
import { RateLimitError } from '@sonar/sdk';
try { await sdk.documents.list();} catch (err) { if (err instanceof RateLimitError) { console.log(`Rate limited. Retry after ${err.retryAfter} seconds`); await new Promise(r => setTimeout(r, (err.retryAfter || 60) * 1000)); }}DocumentNotFoundError
Thrown when a requested document does not exist (HTTP 404).
| Property | Type | Description |
|---|---|---|
code | string | Always 'DOCUMENT_NOT_FOUND' |
status | number | Always 404 |
documentId | string | The ID that was not found |
import { DocumentNotFoundError } from '@sonar/sdk';
try { await sdk.documents.get('doc_nonexistent');} catch (err) { if (err instanceof DocumentNotFoundError) { console.log(`Document ${err.documentId} not found`); }}ValidationError
Thrown for client-side or server-side validation failures (HTTP 400).
| Property | Type | Description |
|---|---|---|
code | string | Always 'INVALID_REQUEST' |
status | number | Always 400 |
errors | FieldError[]? | Array of field-level errors |
Each FieldError: { field: string; code: string; message: string }
import { ValidationError } from '@sonar/sdk';
try { await sdk.documents.export({ documentIds: [] });} catch (err) { if (err instanceof ValidationError) { console.log(err.message); // "At least one document ID is required" if (err.errors) { err.errors.forEach(e => { console.log(` ${e.field}: ${e.message} (${e.code})`); }); } }}Comprehensive Error Handling Pattern
import { SonarSDK, SonarSDKError, AuthenticationError, RateLimitError, DocumentNotFoundError, ValidationError,} from '@sonar/sdk';
async function safeDocumentFetch(sdk: SonarSDK, id: string) { try { return await sdk.documents.get(id); } catch (err) { if (err instanceof DocumentNotFoundError) { console.error(`Document ${err.documentId} does not exist`); return null; } if (err instanceof AuthenticationError) { console.error(`Auth failed: ${err.code} β ${err.message}`); throw err; } if (err instanceof RateLimitError) { const wait = err.retryAfter || 60; console.warn(`Rate limited, retrying in ${wait}s...`); await new Promise(r => setTimeout(r, wait * 1000)); return safeDocumentFetch(sdk, id); } if (err instanceof ValidationError) { console.error('Validation error:', err.errors); throw err; } if (err instanceof SonarSDKError) { console.error(`SDK error [${err.code}]: ${err.message}`); console.error(`Request ID: ${err.requestId}`); throw err; } throw err; }}Error Code Reference
| Error Code | HTTP Status | Error Class | Description |
|---|---|---|---|
MISSING_API_KEY | 401 | AuthenticationError | No API key provided |
INVALID_API_KEY | 401 | AuthenticationError | API key is malformed or invalid |
EXPIRED_API_KEY | 401 | AuthenticationError | API key has expired |
REVOKED_API_KEY | 401 | AuthenticationError | API key has been revoked |
INSUFFICIENT_SCOPE | 403 | AuthenticationError | API key lacks required permissions |
IP_NOT_ALLOWED | 403 | AuthenticationError | Request IP is not in the allowlist |
RATE_LIMIT_EXCEEDED | 429 | RateLimitError | Too many requests |
DOCUMENT_NOT_FOUND | 404 | DocumentNotFoundError | Requested document does not exist |
RESOURCE_NOT_FOUND | 404 | SonarSDKError | Generic resource not found |
INVALID_REQUEST | 400 | ValidationError | Request validation failed |
INVALID_PARAMETER | 400 | ValidationError | Specific parameter is invalid |
EXPORT_LIMIT_EXCEEDED | 400 | ValidationError | Too many documents requested for export |
EXPORT_SIZE_EXCEEDED | 400 | ValidationError | Total export size exceeds limit |
EXPORT_NO_FILES | 400 | ValidationError | No files found for the given document IDs |
INTERNAL_ERROR | 500 | SonarSDKError | Unexpected server error |