Error Codes
When something goes wrong, the SDK throws a CircadifyError instance with a machine-readable code, a human-readable message, and a flag indicating whether the operation can be retried.
Error Format
Section titled “Error Format”All SDK errors are instances of the CircadifyError class, which extends the native Error. You can import both the class and the error code enum for type-safe handling.
import { CircadifyError, CircadifyErrorCode } from '@circadify/sdk';class CircadifyError extends Error { code: CircadifyErrorCode; // Machine-readable error code message: string; // Human-readable description isRetryable: boolean; // Whether the operation can be retried}Use instanceof CircadifyError to distinguish SDK errors from other exceptions:
try { const result = await sdk.measureVitals({ container });} catch (error) { if (error instanceof CircadifyError) { console.error(`[${error.code}] ${error.message} (retryable: ${error.isRetryable})`); }}SDK Error Codes
Section titled “SDK Error Codes”These errors originate from the client-side SDK during the measureVitals() lifecycle.
Initialization Errors
Section titled “Initialization Errors”| Code | Description | Retryable |
|---|---|---|
MISSING_API_KEY | No API key was provided to the constructor | No |
INVALID_API_KEY | API key is malformed or invalid | No |
BROWSER_NOT_SUPPORTED | Browser lacks required APIs (WebAssembly, MediaDevices) | No |
WASM_LOAD_FAILED | Vision Engine WASM modules failed to load | Yes |
Camera Errors
Section titled “Camera Errors”| Code | Description | Retryable |
|---|---|---|
CAMERA_PERMISSION_DENIED | The user denied camera access | No |
CAMERA_NOT_AVAILABLE | No camera found on the device | No |
CAMERA_IN_USE | Camera is already in use by another application | Yes |
Capture Errors
Section titled “Capture Errors”| Code | Description | Retryable |
|---|---|---|
CAPTURE_FAILED | Frame capture encountered an error | No |
FACE_NOT_DETECTED | No face found in the camera feed | Yes |
FACE_DETECTION_TIMEOUT | No face detected within 30 seconds | Yes |
QUALITY_TOO_LOW | Capture quality was too poor to produce results | Yes |
CANCELLED | Measurement was cancelled via AbortController or sdk.cancel() | No |
Network and Processing Errors
Section titled “Network and Processing Errors”| Code | Description | Retryable |
|---|---|---|
NETWORK_ERROR | A network request failed | Yes |
UPLOAD_FAILED | Upload to cloud storage failed | Yes |
TIMEOUT | Polling for results timed out | Yes |
API Error Codes
Section titled “API Error Codes”These errors originate from the Circadify API and are surfaced by the SDK as CircadifyError instances. For the full server-side error reference, see REST API Errors.
| Code | HTTP Status | Description | Retryable |
|---|---|---|---|
API_ERROR | varies | API returned an error response | No |
QUOTA_EXCEEDED | 429 | Monthly scan limit exceeded for your plan | No |
RATE_LIMITED | 429 | Hourly request limit exceeded | Yes |
SESSION_NOT_FOUND | 404 | Session ID does not exist or has expired | No |
SESSION_EXPIRED | 410 | Session timed out before completion | No |
PROCESSING_FAILED | 500 | Server-side inference could not process the measurement | No |
UNKNOWN | varies | An unexpected error occurred | No |
Handling Errors
Section titled “Handling Errors”Basic pattern
Section titled “Basic pattern”Wrap measureVitals() in a try/catch and branch on the error code:
import { CircadifySDK, CircadifyError, CircadifyErrorCode } from '@circadify/sdk';
try { const result = await sdk.measureVitals({ container: document.getElementById('scan-container'), });} catch (error) { if (!(error instanceof CircadifyError)) throw error;
switch (error.code) { case CircadifyErrorCode.CAMERA_PERMISSION_DENIED: showMessage('Please allow camera access to measure your vitals.'); break; case CircadifyErrorCode.QUOTA_EXCEEDED: showMessage('Monthly scan limit reached. Please upgrade your plan.'); break; case CircadifyErrorCode.CANCELLED: // User cancelled — no action needed break; default: if (error.isRetryable) { showRetryButton(error.message); } else { showError(error.message); } }}Retry with backoff
Section titled “Retry with backoff”For retryable errors, implement exponential backoff:
async function measureWithRetry(sdk: CircadifySDK, options: MeasurementOptions, maxRetries = 3) { for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await sdk.measureVitals(options); } catch (error) { if (!(error instanceof CircadifyError) || !error.isRetryable || attempt === maxRetries) { throw error; } const delay = Math.min(1000 * Math.pow(2, attempt), 30000); await new Promise((resolve) => setTimeout(resolve, delay)); } }}Camera permission recovery
Section titled “Camera permission recovery”When the user denies camera access, guide them to their browser settings:
try { const result = await sdk.measureVitals({ container });} catch (error) { if (error instanceof CircadifyError && error.code === CircadifyErrorCode.CAMERA_PERMISSION_DENIED) { showInstructions( 'Camera access is required. Open your browser settings and allow camera access for this site, then refresh the page.' ); }}Next Steps
Section titled “Next Steps”- Events — Monitor errors via event listeners
- REST API Errors — Server-side error reference