Skip to content

Infinite loop in BTreeIndex.takeInternal when using orderBy and limit with undefined indexed values #1186

@1bod

Description

@1bod
  • I've validated the bug against the latest version of DB packages

Describe the bug
When a collection contains items where an indexed field (used in orderBy) evaluates to undefined, and the query uses both .orderBy() and .limit(), the BTreeIndex.takeInternal method enters an infinite loop. This happens because nextPair(undefined) returns [undefined, undefined] (an array) instead of undefined, so the while loop condition pair !== undefined is always true.
To Reproduce
https://stackblitz.com/edit/vitejs-vite-xcu9tcef?file=src%2FApp.vue

<script setup lang="ts">
import {
  createCollection,
  eq,
  useLiveQuery,
  localStorageCollectionOptions,
} from '@tanstack/vue-db';

const collection = createCollection<{
  id: number;
  assignedTo?: { id: number };
}>(
  localStorageCollectionOptions({
    id: 'tasks',
    storageKey: 'app-tasks',
    getKey: (item) => item.id,
  })
);

// Add an item with undefined assignedTo
collection.insert({ id: 1, assignedTo: undefined });

// Query with a filter on assignedTo.id
const { data } = useLiveQuery((q) =>
  q
    .from({ item: collection })
    .where(({ item }) => eq(item.assignedTo.id, 35))
    .orderBy(({ item }) => item.taskDate, 'desc')
    .limit(1)
);

// Insert another item - this triggers the infinite loop
collection.insert({ id: 2, assignedTo: { id: 35 } });

</script>

<template>
  <div>
    {{ data }}
  </div>
</template>

Debug information:

When pausing in the debugger, execution is stuck in btree-index.ts at takeInternal:

Variables at freeze:

pair = [undefined, undefined]
key = undefined
keys = Set with one empty string
result = []
n = 1

Expected behavior
The takeInternal method should handle undefined keys gracefully.

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