Error Handling
AFCore reports failures the same way on Android and iOS. Reads return data or throw an AFException; sign-in and submissions return an AFResult that says whether the operation succeeded. Every message the SDK produces is safe to show a member, so your app can surface errors without writing its own copy.
What you can do
- Show
AFException.messageorAFResult.statusMessagedirectly -- they are member-friendly and never contain hosts, stack traces or server internals. - Branch on
AFException.kindto tell "offline" from "server error" from "session expired", identically on every platform. - Branch on
errorCodewhen the backend refuses a request with a machine-readable reason. - Log
technicalMessagefor support and crash reports (never show it to the member). - Tell "submitted now" from "saved for automatic delivery" with
AFResult.queued.
Key types
| Type | What it is for |
|---|---|
AFResult | Outcome of sign-in and submissions: status, statusMessage, queued, and the exception when one occurred |
AFException | Thrown by reads and failed calls: member-safe message, kind, errorCode, errors (the server's validation messages), technicalMessage |
AFErrorKind | NO_CONNECTION, TIMEOUT, SECURE_CONNECTION, UNAUTHORIZED, CLIENT_ERROR, SERVER_ERROR, INVALID_RESPONSE, UNKNOWN |
Queued submissions. When a self-report, barcode check-in or Fit@Home selfie is made without a connection, the SDK saves it and returns status == true with queued == true. It is delivered automatically once the device is back online -- do not retry it yourself.
Reads that fail. Reads added in 1.12 always throw. Reads that existed in 1.11 return an empty result on failure unless you build the config with throwOnReadFailure(true), which is recommended so that an empty result always means "no data". See Upgrading to 1.12.
Sessions. Token refresh is automatic; your app never handles an expired token. When a session cannot be recovered, authentication().sessionState moves to SESSION_EXPIRED -- see Session Management.
Example
- Android (Kotlin)
- iOS (Swift)
lifecycleScope.launch {
try {
val favorites = AFCore.locations().getFavorites() // 1.12 reads always throw on failure
render(favorites)
} catch (e: AFException) {
when (e.kind) {
AFErrorKind.NO_CONNECTION, AFErrorKind.TIMEOUT -> showRetry(e.message)
else -> showError(e.message)
}
crashReporter.log("AFCore ${e.kind}: ${e.technicalMessage}")
}
}
Task {
do {
let favorites = try await AFCore.shared.locations().getFavorites()
render(favorites)
} catch {
// Kotlin exceptions reach Swift as NSError; the AFException rides in userInfo.
let afe = (error as NSError).userInfo["KotlinException"] as? AFException
switch afe?.kind {
case .noConnection, .timeout: showRetry(afe?.message)
default: showError(afe?.message ?? error.localizedDescription)
}
}
}
For an AFResult, check status first, then queued, and show statusMessage when status is false.
Learn more
See the API Reference for AFResult, AFException and AFErrorKind. Complete integration guides are in AIDE Docs.