Error Handling
The Android SDK throws CircadifyError for expected SDK and API failures. Catch it around measureVitals() and branch on error.code.
Error format
Section titled “Error format”class CircadifyError( val code: CircadifyErrorCode, override val message: String, val details: Map<String, Any?>? = null, cause: Throwable? = null,) : Exception(message, cause) { val isRetryable: Boolean}Basic handling
Section titled “Basic handling”try { val result = sdk.measureVitals( MeasurementOptions( lifecycleOwner = this@MainActivity, previewView = previewView, ), ) showResult(result)} catch (error: CircadifyError) { when (error.code) { CircadifyErrorCode.CAMERA_PERMISSION_DENIED -> showPermissionPrompt() CircadifyErrorCode.CAMERA_NOT_AVAILABLE -> showMessage("No camera found.") CircadifyErrorCode.FACE_DETECTION_TIMEOUT -> showMessage("Make sure your face is visible and well lit.") CircadifyErrorCode.CANCELLED -> Unit else -> { if (error.isRetryable) showRetry(error.message) else showMessage(error.message) } }}Error reference
Section titled “Error reference”Configuration
Section titled “Configuration”| Code | Description | Retryable |
|---|---|---|
MISSING_API_KEY | No API key was provided | No |
INVALID_API_KEY | API key is invalid or revoked | No |
Camera
Section titled “Camera”| Code | Description | Retryable |
|---|---|---|
CAMERA_PERMISSION_DENIED | Camera permission has not been granted | No |
CAMERA_NOT_AVAILABLE | No usable camera was found | No |
CAMERA_IN_USE | Camera is already in use by another app | No |
Capture
Section titled “Capture”| Code | Description | Retryable |
|---|---|---|
CAPTURE_FAILED | Capture failed or timed out before enough frames were collected | No |
FACE_NOT_DETECTED | No face was found in the camera feed | No |
FACE_DETECTION_TIMEOUT | No scan-ready face was detected within the timeout | No |
QUALITY_TOO_LOW | Lighting, motion, or pose quality was too low | No |
CANCELLED | Measurement was cancelled | No |
Network and API
Section titled “Network and API”| Code | Description | Retryable |
|---|---|---|
NETWORK_ERROR | Network request failed | Yes |
UPLOAD_FAILED | Secure upload failed | Yes |
API_ERROR | API returned an error response | No |
SESSION_EXPIRED | Session expired before completion | No |
SESSION_NOT_FOUND | Session does not exist | No |
PROCESSING_FAILED | Processing failed | No |
TIMEOUT | Polling for results timed out | Yes |
QUOTA_EXCEEDED | Account quota was exceeded | No |
RATE_LIMITED | Request rate limit was exceeded | Yes |
UNKNOWN | Unexpected error | No |
Retry with backoff
Section titled “Retry with backoff”Only retry when error.isRetryable is true.
suspend fun measureWithRetry( sdk: CircadifySDK, options: MeasurementOptions, maxRetries: Int = 3,): VitalSignsResult { repeat(maxRetries) { attempt -> try { return sdk.measureVitals(options) } catch (error: CircadifyError) { if (!error.isRetryable || attempt == maxRetries - 1) throw error kotlinx.coroutines.delay(1_000L * (1 shl attempt)) } }
error("unreachable")}Next Steps
Section titled “Next Steps”- Camera & Permissions - Avoid permission errors
- Methods - Measurement lifecycle
- REST API Errors - Server-side error reference