Errors
Beekon errors are typed (Kotlin: subclasses of BeekonError : Throwable; Swift: cases of enum BeekonError: Error; Dart: subclasses of BeekonException; TypeScript: a BeekonError class with a discriminator kind). No global error state, no error codes — pattern-match the type and act on it.
The set is intentionally small.
The taxonomy
Section titled “The taxonomy”| Error | Platforms | When it fires | What to do |
|---|---|---|---|
PermissionDenied | All | ACCESS_FINE_LOCATION not granted (Android), authorization not granted (iOS) | Drive the OS permission prompt, retry start() |
LocationServicesDisabled | All | System-wide location services off; on Android, also fires when Google Play Services is missing or out of date | Show a “turn on Location Services” hint and surface gracefully |
StorageFailure(cause) | All | A SQLite or filesystem failure occurred while reading or writing history | Log cause and surface; should be rare |
These three are the entire surface — there’s no NotInitialised, no NotConfigured, no ServiceFailed, no InternalError. Calling start() without prior configure(...) simply uses the persisted last-known config (or BeekonConfig.default on a fresh install). On Android, the foreground service is started as part of start(); if the OS later kills it, you observe that as a state transition rather than a thrown error (see below).
Handling
Section titled “Handling”suspend fun startTracking() { try { Beekon.start() } catch (e: BeekonError.PermissionDenied) { requestLocationPermissions { granted -> if (granted) startTracking() } } catch (e: BeekonError.LocationServicesDisabled) { showAlert("Turn on Location Services and ensure Google Play Services is up to date.") } catch (e: BeekonError.StorageFailure) { Log.e("beekon", "storage failure", e.cause) }}do { try await Beekon.shared.start()} catch BeekonError.permissionDenied { // drive the WhenInUse → Always prompt; iOS may have silently denied Always permissionManager.requestAlways()} catch BeekonError.locationServicesDisabled { showAlert("Location Services are off in Settings → Privacy & Security.")} catch BeekonError.storageFailure(let cause) { print("beekon storage: \(cause)")}try { await Beekon.instance.start();} on PermissionDenied { // request runtime perms (Android) or drive Always prompt (iOS)} on LocationServicesDisabled { // services off (or no Google Play Services on Android)} on StorageFailure catch (e) { // log e.message; should be rare}import { Beekon, BeekonError } from '@wayq/beekon-rn';
try { await Beekon.start();} catch (e) { if (!(e instanceof BeekonError)) throw e; switch (e.kind) { case 'permissionDenied': // drive the prompt break; case 'locationServicesDisabled': // services off (or no Google Play Services on Android) break; case 'storageFailure': console.error('beekon storage:', e.message); break; }}Errors vs Stopped states
Section titled “Errors vs Stopped states”A useful distinction: errors are thrown when an operation cannot proceed; Stopped states are reported when tracking was running and an external precondition changed.
| Scenario | Surface |
|---|---|
User has never granted permission, you call start() | throws PermissionDenied |
| User revokes permission while tracking | state transitions to Stopped(PermissionDenied) — no exception is thrown |
| Android OS kills the foreground service under memory pressure | state transitions to Stopped(System) — Android only |
Both code paths exist. Observe the state stream for the runtime-revocation case and try/catch around start() calls. Beekon does not auto-resume after a stop — the host app calls start() again once the underlying condition recovers.
What’s not surfaced
Section titled “What’s not surfaced”- Per-fix errors (e.g. one bad fix from the OS provider). Beekon doesn’t filter these — see Locations.
- Notification-channel errors on Android. Beekon creates the channel and continues even if it can’t be displayed.
- Foreground-service start failures on Android. These surface as
Stopped(System)rather than a thrown error.