Skip to content

Order by clause causing maximum call stack size exceeded in Expo React Native app #435

@bradleybernard

Description

@bradleybernard

I recently upgraded from:

@tanstack/db from  0.1.3  to 0.1.6
@tanstack/react-db from 0.1.3 to 0.1.6
@tanstack/query-db-collection from 0.2.2 to 0.2.5

And I found re-running my app I ran into an issue with this stack trace (Expo SDK 54 beta):

   ERROR  [QueryCollection] Error observing query all-groups: [RangeError: Maximum call stack size exceeded] 

  Call Stack
    <anonymous> (node_modules/@tanstack/db/dist/esm/utils/comparison.js:57:27)
    compare (node_modules/@tanstack/db/dist/esm/query/compiler/order-by.js:45:23)
    BNode#indexOf (node_modules/@tanstack/db/dist/esm/utils/btree.js:280:20)
    BNodeInternal#getPairOrNextHigher (node_modules/@tanstack/db/dist/esm/utils/btree.js:503:27)
    BTree#nextHigherPair (node_modules/@tanstack/db/dist/esm/utils/btree.js:126:42)
    BTree#nextHigherKey (node_modules/@tanstack/db/dist/esm/utils/btree.js:137:34)
    nextKey (node_modules/@tanstack/db/dist/esm/indexes/btree-index.js:173:61)
    BTreeIndex#take (node_modules/@tanstack/db/dist/esm/indexes/btree-index.js:175:26)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:262:47)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesToPipelineWithTracking (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:257:34)
    loadNextItems (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:266:46)
    loadMoreIfNeeded (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:243:28)
    maybeRunGraph (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:143:62)
    sendChangesToPipeline (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:160:24)
    sendChangesInRange (node_modules/@tanstack/db/dist/esm/query/live-query-collection.js:276:34)
    <anonymous> (node_modules/@tanstack/db/dist/esm/change-events.js:131:23)
    CollectionImpl#emitEmptyReadyEvent (node_modules/@tanstack/db/dist/esm/collection.js:899:15)
    CollectionImpl#markReady (node_modules/@tanstack/db/dist/esm/collection.js:495:35)
    config.sync.sync$argument_0.markReady (node_modules/@tanstack/db/dist/esm/collection.js:619:25)
    localObserver.subscribe$argument_0 (node_modules/@tanstack/query-db-collection/dist/esm/query.js:94:18)
    listeners.forEach$argument_0 (node_modules/@tanstack/query-core/build/modern/queryObserver.js:428:19)
    forEach (<native>)
    notifyManager.batch$argument_0 (node_modules/@tanstack/query-core/build/modern/queryObserver.js:427:31)
    batch (node_modules/@tanstack/query-core/build/modern/notifyManager.js:40:26)
    <anonymous> (node_modules/@tanstack/query-core/build/modern/queryObserver.js:425:24)
    QueryObserver#updateResult (node_modules/@tanstack/query-core/build/modern/queryObserver.js:403:9)
    QueryObserver#onQueryUpdate (node_modules/@tanstack/query-core/build/modern/queryObserver.js:419:22)
    observers.forEach$argument_0 (node_modules/@tanstack/query-core/build/modern/query.js:373:31)
    forEach (<native>)
    notifyManager.batch$argument_0 (node_modules/@tanstack/query-core/build/modern/query.js:372:29)
    batch (node_modules/@tanstack/query-core/build/modern/notifyManager.js:40:26)
    <anonymous> (node_modules/@tanstack/query-core/build/modern/query.js:371:24)
    Query#setData (node_modules/@tanstack/query-core/build/modern/query.js:53:9)
    Query#fetch (node_modules/@tanstack/query-core/build/modern/query.js:263:19)
    next (<native>)
    asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:17)
    _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:17:27)
    tryCallOne (address at (InternalBytecode.js:1:1180)
    anonymous (address at (InternalBytecode.js:1:1874)

Asking claude about it, it deemed:

  Based on my investigation, I've identified the issue:

  1. The app upgraded from @tanstack/db version 0.1.3 to 0.1.6
  2. The error is a "Maximum call stack size exceeded" in the btree comparison logic when ordering queries
  3. The recursion happens in the useAllGroups query which uses .orderBy(({ group }) => group.id, 'desc')
  4. The error originates when the BalancesCollection query completes and triggers observers, which then triggers the groups query

  The root cause appears to be a bug in @tanstack/db v0.1.6's btree indexing/comparison logic when handling orderBy operations. The recursion loop happens in:
  - loadNextItems -> loadMoreIfNeeded -> maybeRunGraph -> sendChangesToPipeline -> sendChangesToPipelineWithTracking -> back to loadNextItems

I found this PR which got merged recently: #410

I wonder if that is causing an issue?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions