Skip to content

Pagination cursor's embedded sort field isn't cross-checked against the query's sort #119

Description

@cuibonobo

A cursor encodes the sort field it was minted under (field|value|id, cursor.ts:15). On decode, buildWhereClause uses the cursor's field for the keyset column but buildOrderClause uses the query's sort field (query.ts:139-147 vs 155-159). If a cursor minted under sort: createdAt is replayed against sort: version, the keyset predicate (on created_at) and the ORDER BY (on version) disagree — producing skipped or duplicated rows across the page boundary rather than an error.

This is a structurally-incoherent request, exactly the class decodeCursor already rejects for malformed/unknown-field cursors.

Fix

Cross-check the cursor's embedded field against the query's effective sort field (getSortField(query)); on mismatch throw StackQueryError (bad_request/400), consistent with the rest of the cursor codec. One comparison, at the point the cursor is decoded for the query.

Tests

  • A cursor minted under one sort field, replayed with a different sort.field, throws StackQueryError rather than returning an incoherent page
  • Same-field continuation still paginates correctly

Refs

#50 (cursor pagination), #53 (malformed-cursor → 400 bad_request). From docs/design-assessment-2026-07.md §F6.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions