Skip to content

RealmResultsProxy.filtered passes wrapped entities through to Realm — throws under Realm 12 #70

Closed

Description

@1t5j0y

Summary

RealmResultsProxy wraps objects on the way out (map/getAt → createEntity →
new entityClass(realmObject)) but never unwraps them on the way back in:
filtered() forwards its query args verbatim (src/framework/RealmResultsProxy.js:50-56):

filtered(query, ...args) {
    ...
    const realmResultsProxy = RealmResultsProxy.create(this.realmCollection.filtered(query, ...args), this.entityClass);

So any client code that round-trips an entity — get it from a query, hand it back as a
link-equality argument — passes a plain wrapper instance (real object on .that) where
Realm expects a managed object. Realm 10/11 tolerated this; Realm 12's binding rejects it:

Error: Unable to convert an object with ctor 'SubjectType' to a Mixed

Field crash in avni-client's DB-restore path: avniproject/avni-client#2004
(getAllDirectlyAssignable().map(_.identity) → filtered('subjectType = $0', wrapper)).

Every other entry point already handles this

RealmProxy.create (src/framework/RealmProxy.js:61) and RealmProxy.delete (:100) both
unwrap via the existing helper:

const rawObject = getUnderlyingRealmObject(object) || object;

filtered is the only arg-accepting entry point missing it (RealmListProxy has no
filtered; swept).

Proposed fix

Same idiom in RealmResultsProxy.filtered:

filtered(query, ...args) {
    const unwrappedArgs = args.map(arg => getUnderlyingRealmObject(arg) || arg);
    ...this.realmCollection.filtered(query, ...unwrappedArgs)
}

Safe for primitives: getUnderlyingRealmObject requires .that / .realmCollection /
.realmList (RealmCollectionHelper.js), so strings/numbers/dates return null and
|| arg passes them through untouched.

Context

avni-client#2004 worked around the three affected call sites by comparing
link.uuid = $0 with primitive uuids — worth keeping regardless, as it's more robust.
But the gap stays open at the framework level: the next
filtered('link = $0', entityWrapper) anyone writes throws the same Realm 12 error.
This closes it for all queries at once.

Ref: openchs-models 1.33.71, Realm 12.14.2.

Activity

  1. moved this from New Issues to Analysis Complete in Avni Producton Jul 23, 2026
  2. moved this from Analysis Complete to Ready in Avni Producton Aug 18, 2026
  3. moved this from Ready to In Progress in Avni Producton Aug 19, 2026
  4. self-assigned this
    on Aug 19, 2026
  5. added 2 commits that reference this issue on Aug 19, 2026
  6. ombhardwajj commented on Aug 20, 2026

    @ombhardwajj
    Member

    Fixed on 17.2 in two commits.

    b0ba051 — query path, as proposed above. RealmResultsProxy.filtered unwraps its args, element-wise over arrays so IN $0 is covered too. Confirmed against realm 12.14.2 that it rejects both a wrapper and an array of wrappers — though no caller writes an IN query today, so that half closes the gap rather than fixing a live break.

    c339a6d — write path (the extra bit). Reviewing the first fix turned up the same defect going the other way:

    • RealmListProxy.splice / unshift forwarded values to realmList verbatim, wrappers included.
    • RealmListProxy.push read x.that unconditionally, so anything that wasn't a wrapper was written to realm as undefined.
    • PersistedObject.fromEntityList (51 call sites) had the same x.that idiom, while its neighbour fromObject already guarded against it.

    All four now route through one unwrapForRealm in RealmCollectionHelper. RealmProxy.create/delete keep their own variants for now — hot paths, and their divergences want a change of their own.

    ArrayHelper.basePullAt is the live caller of splice and only ever deletes (no values), so it's unaffected — pinned by a test. No realm list holds primitives today, so the undefined write was a dead path. Suite 402 → 415.

    Reaches avni-client only after a v1.33.77 publish; avni-client#2004's call-site workaround stays regardless.

  7. added a commit that references this issue on Aug 20, 2026
  8. moved this from In Progress to Code Review Ready in Avni Producton Aug 20, 2026
  9. moved this from Code Review Ready to In Code Review in Avni Producton Aug 20, 2026
  10. moved this from In Code Review to QA Ready in Avni Producton Aug 20, 2026
  11. moved this from QA Ready to In QA in Avni Producton Aug 24, 2026
  12. moved this from In QA to Done in Avni Producton Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions