Skip to content

ORM: _assertWhereIndexRequirement returns past its own check, so plain-object pipeline wheres silently full-scan #447

Closed

Description

@MikeyZhang75

Summary

_assertWhereIndexRequirement computes a whereExpression, checks it, and then executes a bare return; past it. The function only ever throws for predicate(...) clauses; for a plain-object where — the documented, common form — it is dead code.

The consequence is a silent unbounded-scan class on pipeline union and flatMap sources: _buildFilterExpression is called and discarded, and nothing warns.

Root cause

packages/kitcn/src/orm/query.ts:2794-2798:

    if (!whereExpression) {
      return;
    }

followed immediately by a bare return;. The variable is computed and thrown away.

git log -L 2756,2799 reports a single touching commit (54eeb6d6, Feb 2026), and git log -S "_assertWhereIndexRequirement" shows it was introduced dead in #139 and never edited since. Neither #425 nor #420 touches the function or the word whereExpression.

Correction: the premise that #425 unblocks this is wrong

I previously recorded that completing this assertion was gated on the probe-lowering fix, and that #425 would clear the gate. It does not.

#425's compiled-probe ladder lives in _toConvexQuery / _buildPlanStream. The two call sites that feed this assertion — _buildUnionSourceStream (query.ts:3257) and _applyFlatMapStage (:3297) — still construct raw streams and post-filter, and never reach that ladder. Completing the assertion strictly today would still red convex/orm/pipeline.test.ts:175 and :796.

Suggested fix

This is not a one-line completion. The honest shape:

  1. Route _buildUnionSourceStream and _applyFlatMapStage wheres through the fix(orm): read compiled index-union probes at every stream site #425 _toConvexQuery + _buildPlanStream ladder, so an object where can be index-lowered at all.
  2. Then finish the assertion to throw on whatever remains uncovered.

Doing only step 2 forces pipeline.test.ts:175 and :796 to be rewritten with per-source .withIndex('by_status', ...) — encoding the workaround as contract rather than fixing the cause.

Also fix the flatMap call site's hasConfiguredIndex: Boolean(indexName), which passes the relation FK index and so misreports coverage.

Existing tests

None. git grep "requires .withIndex" across convex/** and packages/kitcn/** hits only the three throw sites in query.ts (:2781, :6074, :6690); no test asserts the pipeline message at :2781, so the dead branch is entirely unobserved.

Environment

  • kitcn 0.32.1
  • convex 1.44.0
  • verified against origin/main at 14bab503

Activity

  1. self-assigned this
    on Sep 5, 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

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions