igloo
Docs / igloohome / BLE SDK / Error Reference

Error Reference

All exceptions thrown by the Igloohome BLE SDK.


Exception Hierarchy

All SDK exceptions extend IglooHomeException, a sealed class with status, source, and message properties.

sealed class IglooHomeException(
    val status: Int,
    val source: Throwable? = null,
    override val message: String? = null,
) : Exception(message, source)

On iOS, every method throws a single Error enum: IgloohomeError, so a single catch IgloohomeError (or a bare catch { }) is enough for every method.

public enum IgloohomeError: Error {
    case bluetooth(source: Error?, message: String?)
    case bluetoothIsTurnedOff(source: Error? = nil, message: String? = nil)
    case lockNotFound(source: Error? = nil, message: String? = nil)
    case pairingFailed(source: Error? = nil, message: String? = nil)
    case connection(source: Error?, message: String?)
    case timeout(source: Error? = nil, message: String? = nil)
    case duplicatePin(source: Error? = nil, message: String? = nil)
    case pinNotFound(source: Error? = nil, message: String? = nil)
    case lockUidNotFound(source: Error? = nil, message: String? = nil)
    case bridgeOffline(source: Error? = nil, message: String? = nil)
    case invalidLockingDirection(source: Error? = nil, message: String? = nil)
    case calibrationFailed(source: Error? = nil, message: String? = nil)
    case lockStorageFull(source: Error? = nil, message: String? = nil)
    case maxScanAttempts(source: Error? = nil, message: String? = nil)
    case missingUid(source: Error? = nil, message: String? = nil)
    case batteryLow(source: Error? = nil, message: String? = nil)
    case dfuStateNotReady(source: Error? = nil, message: String? = nil)
    case dfuJobFailed(source: Error? = nil, message: String? = nil)
    case dfuJobExpired(source: Error? = nil, message: String? = nil)
    case devicePaired
    case hasLinkedDevice(linkedDeviceIds: [String])
    case api(status: Int, source: Error? = nil, message: String? = nil)
    case dfuLibrary(status: Int, source: Error? = nil, message: String? = nil)
    case genericError(_ status: Int, source: Error? = nil, message: String? = nil)
}
// Conforms to LocalizedError — use `error.localizedDescription` for a formatted message.

Error Codes

Exception Code Description
GenericException 1 Catch-all for unhandled errors.
ConnectionException 12 BLE connection failed or device disconnected unexpectedly.
BridgeOfflineException 406 Bridge device is offline (cloud DFU / link operations).
TimeoutException 703 Operation exceeded the time limit. Also used for DfuJobFailedException and DfuJobExpiredException.
DfuJobFailedException 703 Cloud firmware update job failed.
DfuJobExpiredException 703 Cloud firmware update job expired before completion.
BluetoothException 708 Bluetooth is off or unavailable on the device.
DuplicatePinException 880 PIN already exists on the lock.
PinNotFoundException 890 PIN not found on the lock.
InvalidLockingDirectionException 901 Auto-detected locking direction is ambiguous during calibration.
CalibrationFailedException 902 BLE calibration command failed.
DevicePairedException 910 Device is already paired.
HasLinkedDeviceException 910 Device has linked accessories — unlink them first. Carries linkedDeviceIds: List<String>.
LockStorageFullException 912 Lock storage exhausted (no room for more PINs, keycards, or fingerprints).
MaxScanAttemptsException 972 BLE scan retry limit exceeded.
LockUidNotFoundException 980 Device UID not found on the lock (card/fingerprint already removed).
DfuStateNotReadyException 1003 Device not ready for firmware update (door open, DFU mode not entered).
BatteryLowException 1010 Battery too low for firmware update (< 20%, or < 31% for SP2X/SP2E).
DfuLibraryException 1100+ Low-level DFU library error. Status varies.
ApiException varies HTTP error from server API. Status matches the HTTP response code.

iOS does not use numeric status codes for most cases — only IgloohomeError.api, .dfuLibrary, and .genericError carry a status: Int (HTTP-style status from the Partner API or DFU library). The rest of the mapping is by case name:

Android exception iOS equivalent
GenericException IgloohomeError.genericError
ConnectionException IgloohomeError.connection
BridgeOfflineException IgloohomeError.bridgeOffline
TimeoutException IgloohomeError.timeout
DfuJobFailedException IgloohomeError.dfuJobFailed
DfuJobExpiredException IgloohomeError.dfuJobExpired
BluetoothException IgloohomeError.bluetoothIsTurnedOff
DuplicatePinException IgloohomeError.duplicatePin
PinNotFoundException IgloohomeError.pinNotFound
InvalidLockingDirectionException IgloohomeError.invalidLockingDirection
CalibrationFailedException IgloohomeError.calibrationFailed
DevicePairedException IgloohomeError.devicePaired
HasLinkedDeviceException IgloohomeError.hasLinkedDevice(linkedDeviceIds:)
LockStorageFullException IgloohomeError.lockStorageFull
MaxScanAttemptsException IgloohomeError.maxScanAttempts
LockUidNotFoundException IgloohomeError.lockUidNotFound
DfuStateNotReadyException IgloohomeError.dfuStateNotReady
BatteryLowException IgloohomeError.batteryLow
DfuLibraryException IgloohomeError.dfuLibrary(status:)
ApiException IgloohomeError.api(status:)

Error Handling Patterns

Basic

try {
    sdk.lock(deviceId, key)
} catch (e: IglooHomeException) {
    showError("Error ${e.status}: ${e.message}")
}
do {
    try await sdk.lock(deviceId, key: key)
} catch {
    showError(message: error.localizedDescription)
}

Exhaustive

try {
    sdk.lock(deviceId, key)
} catch (e: IglooHomeException) {
    when (e) {
        is IglooHomeException.BluetoothException ->
            showError("Please enable Bluetooth")
        is IglooHomeException.ConnectionException ->
            showError("unexpected bluetooth connection issue")
        is IglooHomeException.TimeoutException ->
            showError("Operation timed out, try again")
        else ->
            showError("Error: ${e.message}")
    }
}
do {
    try await sdk.lock(deviceId, key: key)
} catch IgloohomeError.bluetoothIsTurnedOff {
    showError(message: "Please enable Bluetooth")
} catch IgloohomeError.connection {
    showError(message: "unexpected bluetooth connection issue")
} catch IgloohomeError.timeout {
    showError(message: "Operation timed out, try again")
} catch {
    showError(message: "Error: \(error.localizedDescription)")
}

Every method — lock/unlock included — throws IgloohomeError, whether the failure came from the Bluetooth layer or the server, so one exhaustive catch list covers both. Add more catch IgloohomeError.xxx { } clauses for the cases a given method's own page calls out (pair, createPin, link, DFU, …).

Flow-Based (DFU, Fingerprint)

sdk.performDfu(deviceId, key, firmwareUid).collect { event ->
    when (event) {
        is DfuEvent.Progress -> updateProgressBar(event.percent)
        is DfuEvent.Complete -> showSuccess("Updated to ${event.newFirmwareVersion}")
        is DfuEvent.Failed -> showError("DFU failed: ${event.error.message}")
    }
}
do {
    for try await event in sdk.performDfu(deviceId: deviceId, key: key, firmwareUid: firmwareUid, accessToken: accessToken) {
        switch event {
        case let .progress(percent): updateProgressBar(percent)
        case let .complete(newFirmwareVersion): showSuccess(message: "Updated to \(newFirmwareVersion)")
        }
    }
} catch {
    showError(message: "DFU failed: \(error.localizedDescription)")
}

Retryable vs Terminal

Type Exceptions Recommended Action
Retryable TimeoutException, ConnectionException Retry the operation (user may need to move closer).
Retryable ApiException (5xx) Retry after delay.
Terminal BluetoothException Prompt user to enable Bluetooth.
Terminal DevicePairedException Device already registered — no action needed.
Terminal HasLinkedDeviceException Unlink accessories first using unlink().
Terminal DuplicatePinException Choose a different PIN.
Terminal LockStorageFullException Delete existing access before adding new ones.
Terminal BatteryLowException Wait for battery to charge before DFU.
Terminal CalibrationFailedException Hardware issue — retry calibration from scratch.
Non-fatal LockUidNotFoundException, PinNotFoundException SDK treats these as "already removed" during delete operations.

The same table on iOS, by case name:

Type iOS cases Recommended Action
Retryable IgloohomeError.timeout, .connection, .lockNotFound Retry the operation (user may need to move closer, or wake the lock).
Retryable IgloohomeError.api (5xx) Retry after delay.
Retryable IgloohomeError.pairingFailed Retry pairing with the lock awake and close by.
Terminal IgloohomeError.bluetoothIsTurnedOff Prompt user to enable Bluetooth.
Terminal IgloohomeError.devicePaired Device already registered — no action needed.
Terminal IgloohomeError.hasLinkedDevice Unlink accessories first using unlink().
Terminal IgloohomeError.duplicatePin Choose a different PIN.
Terminal IgloohomeError.lockStorageFull Delete existing access before adding new ones.
Terminal IgloohomeError.batteryLow Wait for battery to charge before DFU.
Terminal IgloohomeError.calibrationFailed Hardware issue — retry calibration from scratch.
Non-fatal IgloohomeError.lockUidNotFound, .pinNotFound SDK treats these as "already removed" during delete operations.