Circadify

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
}
kotlin

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)
        }
    }
}
kotlin

Error reference

Configuration

CodeDescriptionRetryable
MISSING_API_KEYNo API key was providedNo
INVALID_API_KEYAPI key is invalid or revokedNo

Camera

CodeDescriptionRetryable
CAMERA_PERMISSION_DENIEDCamera permission has not been grantedNo
CAMERA_NOT_AVAILABLENo usable camera was foundNo
CAMERA_IN_USECamera is already in use by another appNo

Capture

CodeDescriptionRetryable
CAPTURE_FAILEDCapture failed or timed out before enough frames were collectedNo
FACE_NOT_DETECTEDDeclared but not currently thrown — face absence surfaces as FACE_DETECTION_TIMEOUTNo
FACE_DETECTION_TIMEOUTNo scan-ready face was detected within the timeoutNo
QUALITY_TOO_LOWDeclared but not currently thrown — quality failures surface as CAPTURE_FAILED or FACE_DETECTION_TIMEOUTNo
CANCELLEDMeasurement was cancelledNo

Network and API

CodeDescriptionRetryable
NETWORK_ERRORNetwork request failedYes
UPLOAD_FAILEDSecure upload failedYes
API_ERRORAPI returned an error responseNo
SESSION_EXPIREDSession expired before completionNo
SESSION_NOT_FOUNDSession does not existNo
PROCESSING_FAILEDProcessing failedNo
TIMEOUTPolling for results timed outYes
QUOTA_EXCEEDEDAccount quota was exceededNo
RATE_LIMITEDRequest rate limit was exceededYes
UNKNOWNUnexpected errorNo

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")
}
kotlin
Caution

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