Error handling on iOS

Swift provides built-in support for throwing and catching recoverable errors at runtime. For example, if an operation in your code fails or is not valid, the API throws a HomeError error. This simplifies and streamlines error handling by allowing you to focus only on recoverable errors. You can then provide options, such as letting the user try again or displaying a message like "Structure not found". And because you don't have to explicitly handle every possible exception, your code is less cluttered and consequently, remains more focused on its primary purpose.

An example of how one might handle a recoverable failure:

    let light1 = lightDevices.first
    if let light = light1 {
    do {
      try await structure.move(device: light, to: room)
    } catch let error as HomeError {
      // Code for handling the exception
    }

The following table provides the meanings of HomeError codes that you may encounter:

Table: HomeError codes
Code Meaning
aborted The operation was aborted. This typically appears when there's a concurrency issue such as a sequence check failure or transaction abort.
alreadyExists The resource or entity that you're trying to create already exists. This could be, for example, a named schedule for a thermostat.
cancelled The operation was cancelled, typically by the caller.
dataLoss Unrecoverable data loss or corruption.
deadlineExceeded Deadline expired before operation could complete. For operations that change the state of the system, this error may be returned even if the operation has completed successfully. For example, a successful response from a server could have been delayed long enough for the deadline to expire.
failedPrecondition The operation was rejected because the system is not in a state required for the operation's execution. For example, you might get this message if you called stop on an oven that's already stopped.
internal Internal errors. This means that some invariants expected by the underlying system have been broken. This error code is reserved for serious errors.
invalidArgument Client specified an invalid argument. Note that this differs from `failedPrecondition`. `invalidArgument` indicates arguments that are problematic regardless of the state of the system (for example, a malformed file name).
notFound You specified an entity or resource that can't be found. For example, specifying a nonexistent track id when calling play on a media player device.
outOfRange A parameter exceeded the valid range, based on the current system state. This message occurs when the value is within the range of values that the API call could potentially accept, but doesn't make sense in the present context.
permissionDenied You don't have permission to execute the specified operation. This error code shouldn't be interpreted to mean that the request is otherwise valid.
resourceExhausted Some resource has been exhausted. For example, this could be thrown when one calls dispense(item:amount:unit:presetName:) on a pet feeder device and there's no more food left in the unit.
unauthenticated The caller cannot be identified or the request doesn't have valid authentication credentials.
unavailable The service is unavailable. This is most likely a transient condition, which can be corrected by retrying with a backoff. Note that it's not always safe to retry non-idempotent operations.
unimplemented The requested operation isn't implemented, supported or enabled in this service.
unknown Unknown error. Generally speaking, unknown appears when an error condition occurs that can't be classified using any of the other error codes. For example, this error may be returned when a status value received from an external API that lacks sufficient information as to the root cause.