Error Handling
The SDK is structured into multiple modules and each module will raise its own high level exception type which only has one variant ExceptionDetails(source:SdkException).
This is required due to the way how the language bindings of Rust are being generated and how exceptions are being handled differently across multiple platforms.
Exception Categories
| Exception Type | Description |
|---|---|
SdkManagerException | SdkManager related exception |
SdkConfigurationException | SDK Configuration related exception |
DipException | There was a DIP related exception |
IdentityException | Identity related exception |
IdpException | Identity Protection related exception |
InstanceDiscoveryException | Instance Discovery related exception |
SubscriptionsException | Subscriptions related exceptions |
TokenException | Token Management related exceptions |
CallbackException | Exception thrown by the client’s callback implementation for HTTPCallbackProtocol and StorageCallbackProtocol |
InAppPaymentException | InApp Payments related exception |
LicenseException | Exceptions related to license validity |
The SdkException type contains details about the concrete source of the exception,
Handling Exceptions properly
In the first step, you catch the top-level type, then you evaluate the source field of that top-level type further.
- Swift
- Second Tab
// Executes the given operation and handles known SDK exceptions.
// Returns the operation result or nil if an error occurred.
public func executeAndHandleAPIRequest<T>(operation: () throws -> T?) -> T? {
do {
return try operation()
} catch let SdkManagerException.ExceptionDetails(source) {
print(self.handleError(error: source))
} catch let SdkConfigurationException.ExceptionDetails(source) {
print(self.handleError(error: source))
} catch let DipException.ExceptionDetails(source) {
print(self.handleError(error: source))
} catch let IdentityException.ExceptionDetails(source) {
print(self.handleError(error: source))
} catch let IdpException.ExceptionDetails(source) {
print(self.handleError(error: source))
} catch let InstanceDiscoveryException.ExceptionDetails(source) {
print(self.handleError(error: source))
} catch let SubscriptionsException.ExceptionDetails(source) {
print(self.handleError(error: source))
} catch let TokenException.ExceptionDetails(source) {
print(self.handleError(error: source))
} catch let error as SdkException {
print(self.handleError(error: error))
} catch {
print("\(error)")
}
return nil
}
// Handle the specific SdkException
func handleError(error: SdkException) -> String {
switch error {
case let .Network(reason):
return "Network Error: \(reason)"
case .UserAlreadyExists:
return "Account creation failed: User already exists."
case .UserNotFound:
return "Account not found."
...
}
// Executes the given operation and handles known SDK exceptions.
// Returns the operation result or null if an error occurred.
fun <T> executeAndHandleApiRequest(operation: () -> T?): T? {
return try {
operation()
} catch (e: SdkManagerException.ExceptionDetails) {
println(handleError(e))
null
} catch (e: SdkConfigurationException.ExceptionDetails) {
println(handleError(e))
null
} catch (e: DipException.ExceptionDetails) {
println(handleError(e))
null
} catch (e: IdentityException.ExceptionDetails) {
println(handleError(e))
null
} catch (e: IdpException.ExceptionDetails) {
println(handleError(e))
null
} catch (e: InstanceDiscoveryException.ExceptionDetails) {
println(handleError(e))
null
} catch (e: SubscriptionsException.ExceptionDetails) {
println(handleError(e))
null
} catch (e: TokenException.ExceptionDetails) {
println(handleError(e))
null
} catch (e: SdkException) {
// Catch-all for other SDK exceptions
println(handleError(e))
null
} catch (t: Throwable) {
// Last-resort fallback
println(t.toString())
null
}
}
// Example signature; adapt to your real error type(s)
fun handleError(error: Throwable): String {
// Build a human-friendly message or map to your error model
return "Error: ${error.message ?: error::class.simpleName}"
}