@realm/react - Cannot access realm that has been closed & Accessing object of type X which has been invalidated or deleted
How frequently does the bug occur?
All the time
Description
Preface
I've been migrating a react-native app to use the @realm/react (0.3.2) hooks due to some issues like: https://github.com/realm/realm-js/issues/1031 where deleting records is causing crashes with accessing invalidated objects.
This happens when I have a list view which I'm refetching data for and removing objects no longer valid to display anymore, but also happens intermittently in multiple places.
Seems related to #4441 ?
Currently packages:
"react": "17.0.2",
"react-native": "0.66.0",
"realm": "11.0.0-rc.0",
I got onto using this hooks as someone replied to an issue suggesting the @realm/react hooks fixed this issue, so intended to migrate to them so we could get around these realm related crashes.
The bugs
Still getting "accessing invalidated objects" errors when an object becomes invalidated, but I believe the hooks are supposed to return null instead of crashing?
2.
When I try to use useObject from within a component I most times get a crash suggesting that Realm was closed (see stack traces below, first 2 error logs say undefined is not a function on the object, this comes from line 55 in cachedCollection.js const objectId = object._objectId(); - but the third error says Cannot access realm that has been closed.
Happens consistently on a page from a
Is there a way to force keep open Realm - or to explicitly re-open, I thought thats what the createRealmContext/hooks were meant to manage? Perhaps I missed something in the setup though.
I've found whilst navigating to a page and trying to get an object via this fails:
const cellarDetails = useObject<CellarDetailData>(
CELLAR_DETAIL_COLLECTION,
route.params.itemId
)
If I useQuery and then pick off the item it seems to work fine:
const collection = useQuery<CellarDetailData>(CELLAR_DETAIL_COLLECTION)
const cellarDetails = React.useMemo(() => {
return collection.filtered('code = $0', route.params.itemId)?.[0]
}, [collection])
Below I've added in some code snippets to give an idea of how I've tried slotting the hooks into our existing ones for a minimal change migration (time constraints).
Stacktrace & log output
TypeError: undefined is not a function
This error is located at:
in Detail (at DetailView/index.tsx:50)
in RCTView (at View.js:32)
in View (at styled.tsx:25)
in Unknown (at Box/index.tsx:100)
in Box
in DetailView (at SceneView.tsx:132)
in StaticContainer
in EnsureSingleNavigator (at SceneView.tsx:124)
in SceneView (at useDescriptors.tsx:217)
in RCTView (at View.js:32)
in View (at CardContainer.tsx:281)
in RCTView (at View.js:32)
in View (at CardContainer.tsx:279)
in RCTView (at View.js:32)
in View (at CardSheet.tsx:33)
in mobile(RootComponent) (at renderApplication.js:60), js engine: hermes
ERROR TypeError: undefined is not a function
Warning: Internal React error: Attempted to capture a commit phase error inside a detached tree. This indicates a bug in React. Likely causes include deleting the same fiber more than once, committing an already-finished tree, or an inconsistent return pointer.
Error message:
Error: Exception in HostFunction: Cannot access realm that has been closed.
in Cellar (at SceneView.tsx:132)
in StaticContainer
in EnsureSingleNavigator (at SceneView.tsx:124)
in SceneView (at useDescriptors.tsx:217)
in RCTView (at View.js:32)
in View (at CardContainer.tsx:281)
in RCTView (at View.js:32)
in View (at CardContainer.tsx:279)
in RCTView (at View.js:32)
in View (at CardSheet.tsx:33)
in CardSheet (at Card.tsx:557)
in RCTView (at View.js:32)
in View (at createAnimatedComponent.js:242)
in AnimatedComponent (at createAnimatedComponent.js:295)
in AnimatedComponentWrapper (at Card.tsx:536)
in PanGestureHandler (at GestureHandlerNative.tsx:14)
Can you reproduce the bug?
Yes, always
Reproduction Steps
I've replaced our realm provider with the one from: import { createRealmContext } from '@realm/react', this is created in the app.tsx
Our schemas are designed the old style like:
export const OrdersSchema = {
name: 'OrdersSchema',
properties: {
total: 'PriceSchema?',
orderType: 'string?',
statusDisplay: 'string?',
formattedOrderCreationDate: 'string?',
code: 'string?',
accountId: 'string?',
status: 'StatusSchema?',
displayCPRPurchasePrice: 'bool?',
placed: 'string?',
},
primaryKey: 'code',
}
I tried to just swap out our custom realm hooks like so:
export const useRealmData = <T extends unknown>(
props: RealmDataProps,
): Realm.Results<T> => {
const { schema } = props
const { useQuery } = RealmContext
return useQuery(schema)
}
export const useRealmDataByID = <T>(
props: RealmDataProps,
): (Realm.Object & T) | null => {
const { useObject } = RealmContext
const { schema, primaryKey } = props
return useObject(schema, String(primaryKey))
}
Version
realm: 10.20.0-beta.5 - @realm/react: ^0.3.2
What SDK flavour are you using?
Local Database only
Are you using encryption?
No, not using encryption
Platform OS and version(s)
15.5
Build environment
"react": "17.0.2", "react-native": "0.66.0", "realm": "11.0.0-rc.0", "@realm/react": "0.3.2"
hermes: true
Cocoapods version
No response
@kieran-osgood Thank you for reporting. We will investigate it but one question: does it also happen if you upgrade to v11.0.0-rc.0?
Thanks for checking in! I did try out upgrading to to that rc as well with the same result, probably should've updated the issue with the latest version, will adjust that now
@kieran-osgood One thing I just noticed, the beta and rc version of Realm are only compatible with specific versions of react-native. This is due to us expanding upon the javascript engine provided by react-native (jsi).
I'm curious to know if upgrading to v11.0.0-rc.1 and running the latest [email protected] would cause the issue to go away.
Interesting, I didn't try rc1 as we're on react native 0.66 and didn't want to commit to migrating to the latest react native version (the crashes I was trying to solve just happen to be a week in advance of us delivering to client for production 😅) - I'll see if I can't find the time to test it and get back to you
Believe this all seems to be related to the accessing deleted / invalidated object errors as we got a lot of them recently which seem impossible to 'catch' from crashing us
For now I've left it with the old method of adding listeners and setting state, with a soft delete property, but I might still have to check out the migrations up as we're finding performance issues with high rerendering of these hooks
@kieran-osgood I'm curious why the realm was closed. How have you implemented the <RealmProvider> component? Is it wrapping your navigation stack or just particular screens? When <RealmProvider> is unmounted, it will close the realm.
I would be interested in seeing your navigation layout (i assume you are using React Navigation). I can imagine that if the <RealmProvider/> is being unmounted and remounted on navigation, that some errors could occur. It would be advisable to wrap root Navigation component with the <RealmProvider>. Can you provide us more details on how the root level of your application is implemented?
Yeah I use the RealmProvider component, and so I do get realm working for a while but it consistently crashes when I navigate around so your thought process does sound plausible
Below is a snippet from our app.tsx - I've placed it under the redux and query client from react-query providers, but outside of the navigation stacks (thats in Routes)
<ReactReduxProvider store={store}>
<QueryClientProvider client={queryClient}>
<RealmContext.RealmProvider>
<ApiEmitterProvider>
<ProductProvider>
<Routes />
</ProductProvider>
</ApiEmitterProvider>
</RealmContext.RealmProvider>
</QueryClientProvider>
</ReactReduxProvider>
That does look like a valid setup. We will have to investigate further.
@takameyer @kneth We are facing same issue and we are using wix react-native-navigation so we have to wrap RealmProvider for each screen Here is how we are doing it
Navigation.registerComponent(
'Screen1',
() => props =>
(
<Provider store={store}>
<Screen1 {...props} />
</Provider>
),
(): any => Screen1,
);
Navigation.registerComponent(
'Screen2',
() => props =>
(
<AppProvider id={realmKey}>
<UserProvider>
<RealmProvider>
<Provider store={store}>
<Screen2 {...props} />
</Provider>
</RealmProvider>
</UserProvider>
</AppProvider>
),
(): any => Screen2,
);
Navigation.registerComponent(
'Screen3',
() => props =>
(
<AppProvider id={realmKey}>
<UserProvider>
<RealmProvider>
<Provider store={store}>
<Screen3 {...props} />
</Provider>
</RealmProvider>
</UserProvider>
</AppProvider>
),
(): any => Screen3,
)
As per our internal discussions we figured out either 1 from these 3 should work:-
- Realm should not close by navigating to different screen and coming back
- There should be a way to pass same realm in all screen.
- Even if it is getting closed, how we can open it programatically with some implementation
Hi,
I am facing same problem and below are my dependency versions|
"react-native": "0.68.5", "realm":"11.0.0-rc.0", "@realm/react":"⌃0.4.3"
I have tried wrapping our main navigator component inside RealmProvider and wrapping independent screen inside RealmProvider but still getting same error
In 'object._objectKey()', 'object._objectKey' is undefined
Is there any solution?
This error also happens to me when i save the code and the app is hot reloaded, even though i didn't delete any of the items
Exception in HostFunction: Access to invalidated Results objects, js engine: hermes
I'm using RN 0.71.8 with realm ^11.9.0 and @realm/react ^0.4.3
Sorry for late replys everyone, this has fallen off my radar.
@shridhar48 This is due to using an incompatible version of realm. You need to upgrade to remove this error.
@bao-multiIT Can you make a new issue with some reproduction steps? Your issue could be related to this one, but I want to make sure.
Hi @takameyer , sorry for the super late reply, i've been very busy lately
I've created a new issue here
Hey all, we just released @realm/react version 0.6.0 which includes a flag on the RealmProvider called closeOnUnmount. This can be used in multi-realm situations to ensure that all instances of realm are not closed when the RealmProvider goes out of scope. Try it out and let us know if it helps!