Skip to content

Errors

Beekon errors are typed (Kotlin: subclasses of BeekonError : Throwable; Swift: cases of enum BeekonError: Error; Dart: subclasses of BeekonException). No global error state, no error codes — pattern-match the type and act on it.

The set is small by design. Most errors map to a precondition violation (NotInitialised, NotConfigured) or a permission/availability failure (PermissionDenied, LocationServicesDisabled, NoGmsAvailable). Internal errors should be rare.

ErrorPlatformsWhen it firesWhat to do
NotInitialisedAllstart() called before initialize()Call initialize() once at app startup
NotConfiguredAllstart() called before configure(), or required field missingCall configure(config) with a complete BeekonConfig
PermissionDeniedAllRuntime location permission missingDrive the OS permission prompt, retry start()
LocationServicesDisablediOS, FlutterSystem-wide location services off (Settings → Privacy → Location Services)Show a “turn on Location Services” hint; on Android, surface as Paused(LocationDisabled) instead
NoGmsAvailableAndroid, FlutterDevice has no Google Play Servicesv1 doesn’t support non-GMS devices — surface gracefully
ServiceFailed(cause)Android, FlutterForeground service start failure (quota, OEM kill on start)Log cause, retry; if persistent, OEM-specific workaround likely needed
InternalError(cause)AllAnything else (DB failure, unexpected platform error)Log and surface; should be rare

LocationServicesDisabled is iOS-only on the typed-throw side; on Android the same condition surfaces as Paused(LocationDisabled) via the state stream rather than a thrown error. This is a deliberate platform-specific behaviour — the spec calls it out as not-yet-mirrored.

suspend fun startTracking() {
try {
Beekon.start()
} catch (e: BeekonError.NotInitialised) {
// bug — should never happen if you initialize in Application.onCreate
Log.e("beekon", "init missing", e)
} catch (e: BeekonError.NotConfigured) {
// first run before configure — call configure(...) and retry
} catch (e: BeekonError.PermissionDenied) {
requestLocationPermissions { granted -> if (granted) startTracking() }
} catch (e: BeekonError.NoGmsAvailable) {
showAlert("Beekon requires Google Play Services on this device.")
} catch (e: BeekonError.ServiceFailed) {
Log.e("beekon", "FGS start failed", e.cause)
// typically retry-able; if it persists, the device may need OEM-specific exemption
} catch (e: BeekonError.InternalError) {
Log.e("beekon", "internal", e.cause)
}
}

A useful distinction: errors are thrown when an operation cannot proceed; paused states are reported when tracking was running and an external precondition changed.

ScenarioSurface
User has never granted permission, you call start()throws PermissionDenied
User revokes permission while trackingstate transitions to Paused(PermissionRevoked)start() is not called and does not throw

Both code paths exist. Most apps observe the state stream for the paused case and try/catch around start() calls.

  • Per-position errors (e.g. one bad fix from the OS provider). Beekon doesn’t filter these — see Positions.
  • Notification-channel errors on Android. Beekon creates the channel and continues even if it can’t be displayed.
  • DB write retries. InternalError(cause) only fires after retries are exhausted, which should be rare.