Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RealmException: No such table exists. Error code: 3020. during client reset #1740

Open
SPodjasek opened this issue Jul 4, 2024 · 11 comments

Comments

@SPodjasek
Copy link

What happened?

We've added three new collections to sync schema and during client reset following exceptions were thrown on internal testing pre-production devices:

Android: ClientResetError message: A fatal error occurred during client reset: 'User-provided callback failed', inner error: 'RealmException: No such table exists. Error code: 3020.'
iOS: ClientResetError message: A fatal error occurred during client reset: 'User-provided callback failed', inner error: 'RealmException: Error getting property count. No such table exists. Error code: 3020.'

Application hangs with 'gray-screen' and no information is displayed to the user, but after restart it starts without any issues.

Repro steps

I'm still unable to reproduce this issue.
It never occurred during development, only on pre-production devices in internal testing & test flight.

Version

3.1.0

What Atlas Services are you using?

Atlas Device Sync

What type of application is this?

Flutter Application

Client OS and version

Android 14, iOS 17.5.1

Code snippets

No response

Stacktrace of the exception/crash you're getting

[Android]
          Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: ClientResetError message: A fatal error occurred during client reset: 'User-provided callback failed', inner error: 'RealmException: No such table exists. Error code: 3020.'
       at RealmServices._initialize.<fn>(realm_services.dart:425)
       at ._syncErrorHandlerCallback(config_handle.dart:222)
       at ._FfiCallback_syncErrorHandlerCallback(dart:ffi)
       at RealmLibrary._realm_dart_delete_persistent_handle.#ffiClosure146(realm_bindings.dart)
       at RealmLibrary.realm_scheduler_perform_work(realm_bindings.dart:8712)
       at SchedulerHandle.invoke(scheduler_handle.dart:26)
       at Scheduler._handle(scheduler.dart:45)

[iOS]
          Non-fatal Exception: FlutterError
0  ???                            0x0 RealmServices._initialize.<fn> + 425 (realm_services.dart:425)
1  ???                            0x0 (null)._syncErrorHandlerCallback + 222 (config_handle.dart:222)
2  ???                            0x0 (null)._FfiCallback_syncErrorHandlerCallback (dart:ffi)
3  ???                            0x0 RealmLibrary._realm_dart_delete_persistent_handle.#ffiClosure146 (realm_bindings.dart)
4  ???                            0x0 RealmLibrary.realm_scheduler_perform_work + 8712 (realm_bindings.dart:8712)
5  ???                            0x0 SchedulerHandle.invoke + 26 (scheduler_handle.dart:26)
6  ???                            0x0 Scheduler._handle + 45 (scheduler.dart:45)

Relevant log output

No response

Copy link

sync-by-unito bot commented Jul 4, 2024

➤ PM Bot commented:

Jira ticket: RDART-1066

@nielsenko
Copy link
Contributor

@SPodjasek Can you share the code for your manual reset fallback?

at RealmServices._initialize.(realm_services.dart:425)

@SPodjasek
Copy link
Author

Code below was at version that had issues....

Line 425 is marked by comment.

        onManualResetFallback: (ClientResetError clientResetError) {
          Logger.log(
            'Manual reset fallback',
            name: 'RealmServices',
            error: jsonEncode({
              'message': clientResetError.message,
              'code': {
                'index': clientResetError.code.index,
                'name': clientResetError.code.name,
              },
            }),
          );

          CrashReporting.crashlytics
              .recordError(clientResetError, StackTrace.current, fatal: false);

          // Prompt user to perform a client reset immediately. If they don't,
          // they won't receive any data from the server until they restart the app
          // and all changes they make will be discarded when the app restarts.
          var didUserConfirmReset = true; //showUserAConfirmationDialog();
          if (didUserConfirmReset) {
            // You must close the Realm before attempting the client reset.
            _close();
            // Attempt the client reset.
            Logger.log('Attempting client reset', name: 'RealmServices');
            try {
              clientResetError.resetRealm();    // <------------------------------------------ line 425
              // Navigate the user back to the main page or reopen the
              // the Realm and reinitialize the current page.
              Logger.log('Client reset successful', name: 'RealmServices');
              _initialize(user, encryptionKey);
            } catch (err, stack) {
              // Reset failed.
              // Notify user that they'll need to update the app
              Logger.log(
                'Client reset failed',
                name: 'RealmServices',
                error: err,
              );

              CrashReporting.crashlytics.recordError(err, stack, fatal: true);

              fatal = true;
              notifyListeners();
            }
          }

@SPodjasek
Copy link
Author

@nielsenko Today I've received another error of this kind in newer version, but this time stack trace points to line with just:

_realm = Realm(config);

Config here is FlexibleSyncConfiguration instance with encryption and client reset handler set to RecoverOrDiscardUnsyncedChangesHandler.

Stack trace
Non-fatal Exception: FlutterError
0  ???                            0x0 _raiseLastError.<fn> + 59 (error_handling.dart:59)
1  ???                            0x0 (null).using + 124 (arena.dart:124)
2  ???                            0x0 (null)._raiseLastError + 48 (error_handling.dart:48)
3  ???                            0x0 BoolEx.raiseLastErrorIfFalse + 25 (error_handling.dart:25)
4  ???                            0x0 RealmHandle._getPropertiesMetadata + 460 (realm_handle.dart:460)
5  ???                            0x0 RealmHandle.getObjectMetadata.<fn> + 454 (realm_handle.dart:454)
6  ???                            0x0 (null).using + 124 (arena.dart:124)
7  ???                            0x0 RealmHandle.getObjectMetadata + 449 (realm_handle.dart:449)
8  ???                            0x0 Realm._populateMetadata.<fn> + 212 (realm_class.dart:212)
9  ???                            0x0 MappedIterator.moveNext (dart:_internal)
10 ???                            0x0 new RealmMetadata._ + 874 (realm_class.dart:874)
11 ???                            0x0 Realm._populateMetadata + 212 (realm_class.dart:212)
12 ???                            0x0 new Realm._ + 144 (realm_class.dart:144)
13 ???                            0x0 (null).new Realm + 141 (realm_class.dart:141)
14 ???                            0x0 RealmServices._initialize + 536 (realm_services.dart:536)
15 ???                            0x0 RealmServices._recovery + 789 (realm_services.dart:789)

Looking through code this time it seems that client reset failed, manual reset also failed, after that application tries to remove whole synced realm directory and tries to configure it from scratch.

@IsuruCTS
Copy link

In my case, the problem is embeddedObject schema that I defined in Configuration.flexibleSync is not used in the code.

@SPodjasek
Copy link
Author

During our update we've added two embeddedObjects, but both were used in newly added model.

@nirinchev
Copy link
Member

I was able to reproduce the issue where an embedded object is added without a parent.

@nirinchev nirinchev self-assigned this Jul 15, 2024
@SPodjasek
Copy link
Author

SPodjasek commented Jul 15, 2024

That's interesting because on client-side it was a single commit structured like below (some lines removed):

@RealmModel(ObjectType.embeddedObject)
class _ProfileActivationInput {
  String? label;
  String? type;
}

@RealmModel(ObjectType.embeddedObject)
class _ProfileActivationVerification {
  String? comparison;
  String? error;
  String? result;
  DateTime? ts;
}

@RealmModel()
@MapTo('profile_activation')
class _ProfileActivation {
  @PrimaryKey()
  @MapTo('_id')
  ObjectId? id;

  DateTime? createdAt;
  String? employeeId;
  int? failureCount;
  late List<_ProfileActivationInput> inputs;
  // [...]
  late List<String> values;
  late List<_ProfileActivationVerification> verifications;
}

And all models were added to flexible sync at same commit:

  static final List<SchemaObject> allSchemas = [
    // [...]
    ProfileActivationInput.schema,
    ProfileActivationVerification.schema,
    ProfileActivation.schema,
  ];

@nirinchev
Copy link
Member

That code should be fine - it's possible you're hitting a different issue or some non-obvious manifestation of the existing one.

@lkoehl
Copy link

lkoehl commented Jul 15, 2024

My code looks similar to @SPodjasek code and results in the same error. Any ideas for a workaround?

@nirinchev
Copy link
Member

If you have an easy to run repro case, I should be able to track down what's wrong. Without a clear understanding of the root cause, it's not obvious to me what a workaround would look like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants