Skip to content

[drivers] InMemoryDriver.find applies limit on truthiness, so limit: 0 returns every row — the #6485 defect one layer below the client #6577

Description

@os-project-manager

Found while implementing #6485 (PR to follow). Out of that issue's scope — its file surface was packages/client/src/index.ts only — so filed rather than fixed, per Prime Directive #10.

Fact (measured on origin/main @ 53ef05744, not read)

#6485's ruling was that limit: 0 means "return no records", and it required establishing that the server honours top=0 before shipping the client change. Measuring that turned up a driver that does not.

Probe run against each driver's real find, three rows in the table:

PROBE sql-driver    => {"limit0_rows":0,"limit2_rows":2,"noLimit_rows":3,"offset0_rows":3}
PROBE memory-driver => {"limit0_rows":3,"limit2_rows":2,"noLimit_rows":3}

SqlDriver returns 0 rows for limit: 0. InMemoryDriver returns 3 of 3 — the entire table, for a query that asked for none.

The cause is the same truthiness-vs-presence asymmetry #6485 named, one layer down:

  • packages/drivers/driver-memory/src/memory-driver.ts:315if (query.limit) { results = results.slice(0, query.limit); }
  • versus packages/drivers/driver-sql/src/sql-driver.ts:2773if (query.limit !== undefined) b.limit(query.limit);
  • and packages/drivers/driver-turso/src/remote-transport.ts:1472if (query.limit !== undefined), also presence.

So two shipped drivers answer the same QueryAST with opposite result sets, and the one that disagrees is the one that returns more data than was requested rather than less.

Same shape, three more sites (unmeasured, listed by inspection)

Not probed, so stated as located rather than confirmed:

  • packages/drivers/driver-sql/src/sql-driver.ts:3871findWithWindowFunctions, if (query.limit) builder.limit(query.limit). Truthiness, while findRows in the same file uses presence — so this driver disagrees with itself across two read doors.
  • packages/drivers/driver-sql/src/sql-driver.ts:3911analyzeQuery / explain, same shape. A plan explained for a statement other than the one find would run.
  • packages/drivers/driver-memory/src/memory-analytics.ts:434 and :598 — the $limit pipeline stage and the SQL string builder, both truthiness.

One that is NOT this bug, and should not be "fixed" into one

MongoDBDriver (packages/drivers/driver-mongodb/src/mongodb-driver.ts:231) already tests presence — if (query.limit !== undefined) findOptions.limit = query.limit; — but the MongoDB Node driver defines limit: 0 as no limit, so it returns every row too, for an unrelated reason. Aligning it needs a deliberate guard at that boundary, not the same edit. Worth a decision rather than a patch.

Why this is user-reachable now rather than theoretical

Before #6485 the client dropped limit: 0 on the floor, so no top=0 ever left the SDK and the divergence was unobservable through it. With that fixed, find('task', { limit: 0 }) puts top=0 on the wire, the protocol layer forwards limit: 0 to the engine (measured: findData neither rejects nor ignores it), and the answer now depends on which driver the deployment configured — zero rows on SQL/Turso, every row on memory.

Blocked-by: nothing; independent of #6485's PR, which is correct as it stands for the SQL/Turso path.

Not graded here

Severity judged at filing time is unreliable in both directions, so this is filed plainly and unassigned for the triage round. The two questions the grader will want: whether InMemoryDriver counts as a production surface (it backs LiteKernel, edge/serverless and most of the test suite), and whether the driver contract should state limit: 0 explicitly so the conformance suite can pin it — check:driver-conformance exists and passes today with the two drivers disagreeing.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions