igloo
Docs / iglooworks / BLE SDK / Error Reference

Error Reference

All exceptions thrown by the IglooWorks BLE SDK.


Exception Hierarchy

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

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

On iOS, errors surface as one of two separate Error enums depending on which layer failed: IglooworksError (orchestration/server errors — createPin, pair, link, DFU, etc.) or LockManagerError (raw Bluetooth-layer errors — lock, unlock, scan, etc.). A given method may throw either type, so always end a catch chain with a bare catch { } to be safe. See per-method pages for the type(s) each one throws in practice.

public enum IglooworksError: Error {
    case bluetooth(source: Error?, message: String?)
    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.

IglooworksError.bluetooth is a catch-all for a Bluetooth-layer failure with no closer match among the other cases (usually a low-level transport error, or an unsupported calibration model). Bluetooth-off, no-lock-found and pairing failures are raised as LockManagerError instead — see below.

public enum LockManagerError: Error, Sendable {
    case noLockFound
    case bluetoothIsTurnedOff
    case invalidPairingData
    case pairingMissingCertificate
    case pairingFailed(String?)
    case invalidPairingFlow(String?)
    case deviceDisconnected
    case invalidKeycard
    case invalidCardUid
    case lockCalibrationFailed
    case invalidFirmwareVersion
    case invalidPinType
    case deviceAlreadyPaired
    case dfuStateNotReady
    case lockConnectionError(String?)
    case LockGenericFailureError(String?)
    case LockOperationInProgressError(String?)
    case LockPinNotFoundError(String?)
    case LockInvalidMasterPinLengthError(String?)
    case LockInvalidCustomPinLengthError(String?)
    case LockInvalidVolumeError(String?)
    case LockInvalidPinKeyLengthError(String?)
    case LockInvalidRights(String?)
    case LockPinOccupiedError(String?)
    case LockBlacklistGuestKeyNotFoundError(String?)
    case GenericNotFoundError(String?)
    case LockStorageError(String?)
    case LockReadError(String?)
    case LockTimeoutError(String?)
    case LockMaxAttemptError(String?)
    case CRCFailure(String?)
    case LockVerifyError(String?)
    case LockNotInSchedulerFailure(String?)
    case BluetoothError(String?)
}
// 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 IglooworksError.api, .dfuLibrary, and .genericError carry a status: Int. The rest of the mapping is by case name:

Android exception iOS equivalent
GenericException IglooworksError.genericError
ConnectionException LockManagerError.deviceDisconnected
BridgeOfflineException IglooworksError.bridgeOffline
TimeoutException IglooworksError.timeout or LockManagerError.LockTimeoutError (BLE-layer)
DfuJobFailedException IglooworksError.dfuJobFailed
DfuJobExpiredException IglooworksError.dfuJobExpired
BluetoothException LockManagerError.bluetoothIsTurnedOff
DuplicatePinException IglooworksError.duplicatePin
PinNotFoundException IglooworksError.pinNotFound
InvalidLockingDirectionException IglooworksError.invalidLockingDirection
CalibrationFailedException IglooworksError.calibrationFailed / LockManagerError.lockCalibrationFailed
DevicePairedException IglooworksError.devicePaired / LockManagerError.deviceAlreadyPaired
HasLinkedDeviceException IglooworksError.hasLinkedDevice(linkedDeviceIds:)
LockStorageFullException IglooworksError.lockStorageFull
MaxScanAttemptsException IglooworksError.maxScanAttempts
LockUidNotFoundException IglooworksError.lockUidNotFound
DfuStateNotReadyException IglooworksError.dfuStateNotReady / LockManagerError.dfuStateNotReady
BatteryLowException IglooworksError.batteryLow
DfuLibraryException IglooworksError.dfuLibrary(status:)
ApiException IglooworksError.api(status:)

Error Handling Patterns

Basic

try {
    sdk.lock(deviceId, key)
} catch (e: IglooWorksException) {
    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: IglooWorksException) {
    when (e) {
        is IglooWorksException.BluetoothException ->
            showError("Please enable Bluetooth")
        is IglooWorksException.ConnectionException ->
            showError("unexpected bluetooth connection issue")
        is IglooWorksException.TimeoutException ->
            showError("Operation timed out, try again")
        else ->
            showError("Error: ${e.message}")
    }
}
do {
    try await sdk.lock(deviceId, key: key)
} catch LockManagerError.bluetoothIsTurnedOff {
    showError(message: "Please enable Bluetooth")
} catch LockManagerError.deviceDisconnected {
    showError(message: "unexpected bluetooth connection issue")
} catch LockManagerError.LockTimeoutError {
    showError(message: "Operation timed out, try again")
} catch {
    showError(message: "Error: \(error.localizedDescription)")
}

Because lock/unlock throw LockManagerError directly (not IglooworksError), the exhaustive catch list above only needs to match LockManagerError cases. Methods that orchestrate a server call too (pair, createPin, link, DFU, …) can throw IglooworksError cases as well — add catch IglooworksError.xxx { } clauses for those as shown on each method's own page.

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 {
    let events = try await sdk.performDfu(deviceId: deviceId, key: key, firmwareUid: firmwareUid)
    for try await event in events {
        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 IglooworksError.timeout, LockManagerError.LockTimeoutError, LockManagerError.deviceDisconnected Retry the operation (user may need to move closer).
Retryable IglooworksError.api (5xx) Retry after delay.
Terminal LockManagerError.bluetoothIsTurnedOff Prompt user to enable Bluetooth.
Terminal IglooworksError.devicePaired, LockManagerError.deviceAlreadyPaired Device already registered — no action needed.
Terminal IglooworksError.hasLinkedDevice Unlink accessories first using unlink().
Terminal IglooworksError.duplicatePin Choose a different PIN.
Terminal IglooworksError.lockStorageFull Delete existing access before adding new ones.
Terminal IglooworksError.batteryLow Wait for battery to charge before DFU.
Terminal IglooworksError.calibrationFailed, LockManagerError.lockCalibrationFailed Hardware issue — retry calibration from scratch.
Non-fatal IglooworksError.lockUidNotFound, .pinNotFound SDK treats these as "already removed" during delete operations.