Error Codes
Reference for all Circadify SDK and API 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
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/web-sdk';typescriptclass CircadifyError extends Error {
code: CircadifyErrorCode; // Machine-readable error code
message: string; // Human-readable description
isRetryable: boolean; // Whether the operation can be retried
}typescriptUse instanceof CircadifyError to distinguish SDK errors from other exceptions:
try {
const video = document.querySelector('video')!;
const result = await sdk.measureVitals({ videoElement: video });
} catch (error) {
if (error instanceof CircadifyError) {
console.error(`[${error.code}] ${error.message} (retryable: ${error.isRetryable})`);
}
}typescriptSDK Error Codes
These errors originate from the client-side SDK during the measureVitals() lifecycle.
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 | Required SDK runtime assets failed to load | Yes |
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
| 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
| Code | Description | Retryable |
|---|---|---|
NETWORK_ERROR | A network request failed | Yes |
UPLOAD_FAILED | Secure upload failed | Yes |
TIMEOUT | Polling for results timed out | Yes |
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 |
RATE_LIMITED | 429 | Sandbox request rate limit, or monthly scan quota, exceeded | Yes (sandbox rate limit) / No (monthly quota) |
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 | The measurement could not be processed | No |
UNKNOWN | varies | An unexpected error occurred | No |
Retryable errors (isRetryable: true) are safe to retry with exponential backoff. A RATE_LIMITED from the sandbox request rate limit is retryable (back off, then retry); a RATE_LIMITED caused by an exhausted monthly scan quota is not — check your Usage page.
Handling Errors
Basic pattern
Wrap measureVitals() in a try/catch and branch on the error code:
import { CircadifySDK, CircadifyError, CircadifyErrorCode } from '@circadify/web-sdk';
try {
const result = await sdk.measureVitals({
videoElement: document.getElementById('preview') as HTMLVideoElement,
});
} 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.CANCELLED:
// User cancelled — no action needed
break;
default:
if (error.isRetryable) {
showRetryButton(error.message);
} else {
showError(error.message);
}
}
}typescriptRetry 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));
}
}
}typescriptCamera permission recovery
When the user denies camera access, guide them to their browser settings:
try {
const video = document.querySelector('video')!;
const result = await sdk.measureVitals({ videoElement: video });
} 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.'
);
}
}typescriptNever retry CAMERA_PERMISSION_DENIED or MISSING_API_KEY errors. These require user or configuration changes before they can succeed.
Next Steps
- Events — Monitor errors via event listeners
- REST API Errors — Server-side error reference