realm / realm-dart

Realm is a mobile database: a replacement for SQLite & ORMs.
Apache License 2.0
756 stars 84 forks source link

RealmException: Error setting property Stock.ebmSynced Error: RealmException: No such table exists. Error code: 3020. #1662

Open richard457 opened 4 months ago

richard457 commented 4 months ago

What happened?

I am trying to update data inside isolate then I encounter the above error

Repro steps

 https://github.com/yegobox/realm-issue

Version

realm: ^2.2.1

What Atlas Services are you using?

Atlas Device Sync

What type of application is this?

Flutter Application

Client OS and version

Android, Macos, IOS

Code snippets

 https://github.com/yegobox/realm-issue

Stacktrace of the exception/crash you're getting

E/flutter (23158): RealmException: Error setting property Stock.ebmSynced Error: RealmException: No such table exists. Error code: 3020.
E/flutter (23158): #0      RealmCoreAccessor.set (package:realm_dart/src/realm_object.dart:335:7)
E/flutter (23158): #1      RealmObjectBase.set (package:realm_dart/src/realm_object.dart:385:22)

Relevant log output

No response

sync-by-unito[bot] commented 4 months ago

➤ PM Bot commented:

Jira ticket: RDART-1017

nielsenko commented 4 months ago

@richard457 The error is telling you that the Stock table doesn't exists. Your code snippet don't show me the actual model definition, nor can I see the backend schema, but you need to ensure these line up.

richard457 commented 4 months ago

Yes, but I have the table both locally and in atlas sync, I could not see why it is complaining about that it does not exist as I have it and I did run dart run realm generate, it is important to note that I only get the error when in isolate.

nielsenko commented 4 months ago

@richard457 What is Variant then?

nielsenko commented 4 months ago

@richard457 The first code snippet works with Variant. I don't see how Stock comes into play, as Variant doesn't reference Stock at all. I cannot really debug your issue like this, so I suggest you try to create a smaller reproduction project I can work with.

richard457 commented 4 months ago

Let me try to re-product the issue and get back to you.

richard457 commented 4 months ago

I was able to reproduce issue please find the repo here https://github.com/yegobox/realm-issue

richard457 commented 4 months ago

cc @nielsenko

nielsenko commented 4 months ago

@richard457 That does not really constitute a minimal reproduction in my opinion.

However I did take it for a spin.

To setup the backend I created a new App Service, enabled debug mode to allow client to determine schema, setup rules - I just allowed read-write for all on both Stock and Variant collection. And added an api key for authentication.

Client side I implemented the missing AppSecrets to match backend, added tracing, and disabled encryption to make debugging easier. That was all.

The app runs without exception on my end, but doesn't seem to do anything interesting/useful.

richard457 commented 4 months ago

It is od that you did not reproduce the bug, I will keep digging and see if I find something useful;

nielsenko commented 4 months ago

@nirinchev made me aware that you are passing an async function as callback to writeAsync. In particular inside that callback when you await RWTax().saveItem(variation: variant); you can/will yield to another async context.

I don't believe it should cause: Error code: 3020 though.

richard457 commented 4 months ago

The error always is triggered when attempt to update realm managed object inside isolate

 variant.ebmSynced = true;
nirinchev commented 4 months ago

As Kasper mentioned, the problem appears to be that you're passing in an async callback in realm.writeAsync. This API is intended to take in a synchronous function and passing in a future will not work as you intend it to - i.e. the transaction will be committed immediately and you'll exit the write block when you hit the first await. This is something we'd need to guard against, but my guess is that if you change your code not to pass in a future, it will start working.

richard457 commented 4 months ago

Okay noted, but also did intentional update inside realm.write((){}); inside isolate it throw sig fault error as well.

nirinchev commented 4 months ago

No, that is definitely not expected. I'll need to try and repro this and get back to you.

richard457 commented 3 months ago

Also after digging for a while, I realized you can not use compute to handle isolate with realm, also confirm 100% that you can not update managed objects inside isolate, also as @nielsenko pointed out, It is confusing for a developer to be given realm.writeAsync (() {} and expect to not put any async function inside....

nielsenko commented 3 months ago

@richard457 As you may be aware we have been discussing a PR to address this. However we have decided on throwing an error instead of allowing you to pass an async callback to writeAsync. The reason is that we prefer to notch our users towards short transactions, especially when using multiple isolates.

So make sure your web requests and other async work happens outside the transaction, and use a normal synchronous callback for the actual writeAsync callback.

Also, you can 100% 😄 update managed realm objects inside another isolate, but you cannot transfer them between isolates. This is because realm objects depends on Finalizable, etc. which cannot be transferred between isolates. See https://api.flutter.dev/flutter/dart-isolate/SendPort/send.html for details.

However you can pass a primary key to another isolate, have the isolate update the corresponding object and see the change in the original isolate.

I hope this helps.

BTW, we will not be very active on github this week, but you can always reach out to our TSEs, if you need further help.

whaleHan commented 3 months ago

I also encountered this problem when creating a new data table, and the data table was not created successfully. version: 2.3.0 This problem did not occur when I rolled the version back to 2.1.0, and the new data table could be created successfully.

SPodjasek commented 2 months ago

I'm receiving similar exceptions with Realm 3.1.0, but during synced realm upgrade when new collections were added to synchronization and RecoverOrDiscardUnsyncedChangesHandler falls back to onManualResetFallback...

On Android it's: ClientResetError message: A fatal error occurred during client reset: 'User-provided callback failed', inner error: 'RealmException: No such table exists. Error code: 3020.' And on iOS it's: 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.'

Is it possibly related?

nielsenko commented 2 months ago

@SPodjasek While this is the same error code, your issue occur during client reset. Could I ask you to create a separate issue to avoid mixing things up?

SPodjasek commented 2 months ago

@nielsenko Moved to new issue