Error Handling
Handle Circadify Android SDK errors from camera, capture, network, API, and cancellation paths.
The Android SDK throws CircadifyError for expected SDK and API failures. Catch it around measureVitals() and branch on error.code.
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
}kotlinBasic 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)
}
}
}kotlinError reference
Configuration
| Code | Description | Retryable |
|---|---|---|
MISSING_API_KEY | No API key was provided | No |
INVALID_API_KEY | API key is invalid or revoked | No |
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
| Code | Description | Retryable |
|---|---|---|
CAPTURE_FAILED | Capture failed or timed out before enough frames were collected | No |
FACE_NOT_DETECTED | Declared but not currently thrown — face absence surfaces as FACE_DETECTION_TIMEOUT | No |
FACE_DETECTION_TIMEOUT | No scan-ready face was detected within the timeout | No |
QUALITY_TOO_LOW | Declared but not currently thrown — quality failures surface as CAPTURE_FAILED or FACE_DETECTION_TIMEOUT | No |
CANCELLED | Measurement was cancelled | No |
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
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")
}kotlinCaution
Do not automatically retry camera, capture-quality, permission, API-key, or quota errors. These require user action, better scan conditions, or configuration changes.
Next Steps
- Camera & Permissions - Avoid permission errors
- Methods - Measurement lifecycle
- REST API Errors - Server-side error reference