Skip to content

fix: after filter with limit returns oldest records instead of newest in list endpoints - #2351

Open
lav45 wants to merge 2 commits into
svix:mainfrom
lav45:fix-filter-with-limit
Open

fix: after filter with limit returns oldest records instead of newest in list endpoints#2351
lav45 wants to merge 2 commits into
svix:mainfrom
lav45:fix-filter-with-limit

Conversation

@lav45

@lav45 lav45 commented May 27, 2026

Copy link
Copy Markdown

Motivation

When using the after query parameter together with limit in list endpoints (GET /app/{appId}/msg, GET /app/{appId}/endpoint/{endpointId}/msg), the response returns the oldest records in the time window instead of the newest.

Example with 5 messages (msg1 oldest → msg5 newest):

  • ?after= → [msg5, msg4, msg3, msg2, msg1] ✓
  • ?after=&limit=2 → [msg2, msg1] ✗ (expected [msg5, msg4])

The bug is in filter_and_paginate_time_limited (server/svix-server/src/v1/utils/mod.rs:227). When after is passed without an iterator, the query uses ORDER BY id ASC expecting an in-memory reverse afterward. However, data.truncate(limit) runs
before data.reverse() in list_response_inner, so the newest records are discarded before the reversal can recover them.

Solution

Remove the after-only case (None, None, Some(_)) from the ASC branch so it falls through to ORDER BY id DESC — the same ordering used by all other cases. This makes truncate correctly retain the newest records, and no reversal is needed.

The after filter still applies its lower-bound WHERE id > start_id(after) constraint unchanged, so the time-window semantics are preserved. Pagination via iterator and prev_iterator continues to work correctly.

@lav45
lav45 requested a review from a team May 27, 2026 14:03
@lav45
lav45 requested a review from a team as a code owner May 27, 2026 14:03
@svix-james

Copy link
Copy Markdown
Contributor

Hi! Thanks for the PR! This is a known behavior with our API. Unfortunately, because we have customers who depend on this current API behavior, we haven't been able to make changes yet to make things more intuitive. Stay tuned, though, as we hope to have a solution in the near future.

The way you can work around this for now, as you may have already discovered, is to pass prevIterator on subsequent requests to get the later messages.

@lav45

lav45 commented Jun 5, 2026

Copy link
Copy Markdown
Author

It is possible to start forming v2.0.0-RC for now ;)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants