Handle Sync Errors - React Native SDK
On this page
- Sync Error Handler
- Add a Generic Sync Error Handler
- Handle Compensating Write Errors
- Handle Client Reset Errors
- Client Reset Modes
- Automatic vs. Manual Client Reset
- Client Reset with Recovery
- Recover Unsynced Changes Mode
- Recover or Discard Unsynced Changes Mode
- Manual Client Reset Fallback
- Discard Unsynced Changes Mode
- Discard Unsynced Changes after Breaking Schema Changes
- Manual Mode
- Manual Data Recovery
- Test Client Reset Handling
When you use Atlas Device Sync in your Realm app, you can encounter a new class of errors: sync errors.
The Realm React Native SDK can help you detect and handle sync errors. For example, you can write your own sync error handler to respond to specific errors. You can also define how your client app handles client resets.
Sync Error Handler
You should set an error handler for apps that use Atlas Device Sync. A generic error handler will detect and respond to failed sync-related API calls.
Add a Generic Sync Error Handler
A generic sync error handler is a good way to keep track of sync errors. Using FlexibleSyncConfiguration, you can define your error handling behavior.
To add a generic sync error handler:
Write an error handler function.
Create a
FlexibleSyncConfiguration
object for yourRealmProvider
.Pass your error handler to the
onError
property of theFlexibleSyncConfiguration
object.
const syncConfigWithErrorHandling = { flexible: true, onError: (_session, error) => { console.log(error); }, }; function RealmWithErrorHandling() { return ( <RealmProvider sync={syncConfigWithErrorHandling}> <RestOfApp /> </RealmProvider> ); }
Tip
For a list of common Device Sync errors and how to handle them, refer to Sync Errors in the App Services Device Sync documentation.
Handle Compensating Write Errors
You may want your sync error handler to specifically address compensating write errors in a way that makes sense for your app. The CompensatingWriteError class can help you identify and react to compensating write errors in your custom error handler.
To handle compensating write errors:
Write an error handler function that uses
CompensatingWriteError
to identify compensating write errors.Create a
FlexibleSyncConfiguration
object for yourRealmProvider
.Pass your error handler to the
onError
property of theFlexibleSyncConfiguration
object.
export const CompensatingWriteErrorHandling = () => { const [error, setError] = useState<CompensatingWriteError | undefined>( undefined, ); // Create a callback for sync error handling using CompensatingWriteError const errorCallback: ErrorCallback = (_session, error) => { if (error instanceof CompensatingWriteError) { // Handle the compensating write error as needed console.debug({ code: error.code, name: error.name, category: error.category, message: error.message, url: error.logUrl, writes: error.writes, }); setError(error); } }; return ( <AppProvider id={APP_ID}> <UserProvider fallback={LogIn}> <RealmProvider schema={[Person, Turtle]} sync={{ flexible: true, onError: errorCallback, }}> <CompensatingWriteErrorHandler error={error} /> </RealmProvider> </UserProvider> </AppProvider> ); };
Handle Client Reset Errors
A client reset error is a type of sync error where a client realm cannot sync data with the Atlas App Services backend. Clients in this state may continue to run and save data locally but cannot send or receive sync changesets until they perform a client reset.
To learn about the causes of and modes for handling client resets, refer to Device Sync Client Resets in the App Services documentation.
Client Reset Modes
You can specify which client reset mode your app should use to restore the realm to a syncable state:
Recover unsynced changes mode: When you choose this mode, the client attempts to recover unsynced changes. Choose this mode when you do not want to fall through to discard unsynced changes.
Recover or discard unsynced changes mode: The client first attempts to recover changes that have not yet synced. If the client cannot recover unsynced data, it falls through to discard unsynced changes but continues to automatically perform the client reset. Choose this mode when you want to enable automatic client recovery to fall back to discard unsynced changes.
Discard unsynced changes mode: Restores the realm to a syncable state by discarding changes made since the last sync.
Manual recovery mode: Downloads a new copy of the realm, and moves the unsyncable realm to a backup. Migrate unsynced data from the backup copy of the realm to the new syncable copy.
Automatic vs. Manual Client Reset
The Realm SDKs provide client reset modes that automatically handle most client reset errors.
Automatic client reset modes restore your local realm file to a syncable state without closing the realm or missing notifications. The following client reset modes support automatic client resets:
Recover unsynced changes mode
Recover or discard unsynced changes mode
Discard unsynced changes mode
The differences between these modes are based on how they handle changes on the device that have not yet synced to the backend. Only manual recovery mode does not perform an automatic client reset.
Choose recover unsynced changes mode to handle most client reset scenarios automatically. This attempts to recover unsynced changes when a client reset occurs.
If your app requires specific client reset logic that can't be handled automatically, you may want or need to add a manual client reset handler to the automatic client reset mode.
Client Reset with Recovery
New in version realm@10.23.0
.
Client Recovery is a feature that is enabled by default when you configure Device Sync. When Client Recovery is enabled, Realm automatically manages the client reset process in most cases. The client can recover unsynced changes when there are no schema changes, or non-breaking schema changes.
To use Client Recovery, configure your realm with one of the following client reset modes:
Recover unsynced changes mode
Recover or discard unsynced changes
When Client Recovery is enabled, these rules determine how objects are integrated, including how conflicts are resolved when both the backend and the client make changes to the same object:
Objects created locally that were not synced before client reset are synced.
If an object is deleted on the server, but is modified on the recovering client, the delete takes precedence and the client discards the update.
If an object is deleted on the recovering client, but not the server, then the client applies the server's delete instruction.
In the case of conflicting updates to the same field, the client update is applied.
For more information about configuring Client Recovery, refer to Client Recovery in the App Services documentation.
Client Recovery cannot succeed when your app makes breaking schema changes. A breaking change is a change that you can make in your server-side schema that requires additional action to handle. In this scenario, client reset falls back to a manual error client reset fallback.
For information on breaking vs. non-breaking schema changes, refer to Breaking vs. Non-Breaking Change Quick Reference in the App Services documentation.
Recover Unsynced Changes Mode
When you choose recover unsynced changes mode, the client attempts to recover unsynced changes with Client Recovery. Choose this mode when you do not want to fall through to discard unsynced changes.
To handle client resets with the recover unsynced changes mode,
pass a ClientResetConfiguration
to the clientReset
field of your
FlexibleSyncConfiguration.
Include these properties in the ClientResetConfiguration
:
mode
: Set to"recoverUnsyncedChanges"
.onBefore
: Optional. Callback function invoked before the SDK executes this mode, when the SDK receives a client reset error from the backend. Provides a copy of the realm.onAfter
: Optional. Callback function invoked after the SDK successfully executes this mode. Provides instances of the realm before and after the client reset.onFallback
: Optional. Callback function which the SDK invokes only if the automatic recovery fails. For more information, refer to the Manual Client Reset Fallback section.
The following example implements recover unsynced changes mode:
Recover or Discard Unsynced Changes Mode
In recover or discard unsynced changes mode, the client first attempts to recover changes that have not yet synced. If the client cannot recover unsynced data, it falls through to discard unsynced changes but continues to automatically perform the client reset. Choose this mode when you want to enable automatic client recovery to fall back to discard unsynced changes.
Do not use recover or discard unsynced changes mode if your application cannot lose local data that has not yet synced to the backend.
To handle client resets with the recover or discard unsynced changes mode,
pass a ClientResetConfiguration
to the clientReset
field of your
FlexibleSyncConfiguration.
Include these properties in the ClientResetConfiguration
:
mode
: Set to"recoverOrDiscardUnsyncedChanges"
.onBefore
: Optional. Callback function invoked before the SDK executes this mode, when the SDK receives a client reset error from the backend. Provides a copy of the realm.onAfter
: Optional. Callback function invoked after the SDK successfully executes this mode. Provides instances of the realm before and after the client reset.onFallback()
: Optional. Callback function which the SDK invokes only if both the automatic recovery and and discarding changes fails. For more information, refer to the Manual Client Reset Fallback section.
The following example implements recover unsynced changes mode:
Manual Client Reset Fallback
If the client reset with recovery cannot complete automatically, like when there are breaking schema changes, the client reset process falls through to a manual error handler. This may occur in either of the client reset with recovery modes, recover unsynced changes and recover or discard unsynced changes.
You must provide a manual client reset implementation
in the SyncConfiguration.onFallback()
callback. onFallback()
takes two
arguments:
session
: Session object representing the state of the Device Sync session.path
: String with the path to the current realm file.
The following example demonstrates how you can manually handle this error case by discarding all unsynced changes:
Discard Unsynced Changes Mode
New in version realm@10.11.0
.
Changed in version realm@10.23.0
: Mode renamed from "discardLocal" to "discardUnsyncedChanges". Both currently work, but in a future version, "discardLocal" will be removed. "clientResetBefore" and "clientResetAfter" callbacks renamed to "onBefore" and "onAfter", respectively.
Discard Unsynced Changes mode permanently deletes all local unsynced changes made since the last successful sync. You might use this mode when your app requires client recovery logic that is not consistent with automatic Client Recovery, or when you don't want to recover unsynced data.
Do not use discard unsynced changes mode if your application cannot lose local data that has not yet synced to the backend.
To handle client resets with the discard unsynced changes mode,
pass a ClientResetConfiguration
to the clientReset
field of your
FlexibleSyncConfiguration.
Include these properties in the ClientResetConfiguration
:
mode
: Set to"discardUnsyncedChanges"
.onBefore
: Optional. Callback function invoked before the SDK executes this mode, when the SDK receives a client reset error from the backend. Provides a copy of the realm.onAfter
: Optional. Callback function invoked after the SDK successfully executes this mode. Provides instances of the realm before and after the client reset.
The following example implements discard unsynced changes mode:
Discard Unsynced Changes after Breaking Schema Changes
If your application experiences a breaking schema change, discard
unsynced changes mode cannot handle the resulting client reset
automatically. Instead, you must provide a manual client reset
implementation in the SyncConfiguration error()
callback. The following
example demonstrates how you can manually handle this error case by
discarding all unsynced changes:
Note
Discard with Recovery
If you'd like to attempt to recover unsynced changes, but but discard any changes that cannot be recovered, refer to the recover or discard unsynced changes mode section.
Manual Mode
Changed in version realm@10.23.0
: onManual callback added
In manual mode, you define your own client reset handler. You might want to use a manual client reset handler if the Automatic Recovery logic does not work for your app and you can't discard unsynced local data.
To handle client resets with manual mode,
pass a ClientResetConfiguration
to the clientReset
field of your
FlexibleSyncConfiguration.
Include these properties in the ClientResetConfiguration
:
mode
: Set to"manual"
.onManual
: Optional. Callback function invoked when the client reset occurs. Provides information about the sync session and the path to the current realm. If you don't set theonManual
error handler, the client reset error falls back to the general sync error handler.
Manual Data Recovery
To recover data from a manual client reset requires significant amounts of code, schema concessions, and custom conflict resolution logic. If you need to implement your own custom client reset logic, see the Advanced Guide to Manual Client Reset Data Recovery.
Test Client Reset Handling
You can manually test your application's client reset handling by terminating and re-enabling Device Sync.
When you terminate and re-enable Sync, clients that have previously connected with Sync are unable to connect until after they perform a client reset. Terminating Sync deletes the metadata from the server that allows the client to synchronize. The client must download a new copy of the realm from the server. The server sends a client reset error to these clients. So, when you terminate Sync, you trigger the client reset condition.
To test client reset handling:
Write data from a client application and wait for it to synchronize.
Terminate and re-enable Device Sync.
Run the client app again. The app should get a client reset error when it tries to connect to the server.
Warning
While you iterate on client reset handling in your client application, you may need to terminate and re-enable Sync repeatedly. Terminating and re-enabling Sync renders all existing clients unable to sync until after completing a client reset. To avoid this in production, test client reset handling in a development environment.