fix: add deterministic tiebreaker to all paginated chat queries (#22387)

Add Chat.id as a secondary sort key to all paginated chat queries
that use offset/limit pagination. When multiple chats share the same
updated_at timestamp, the database does not guarantee a stable order
across page boundaries, causing chats to appear on multiple pages.

This produces duplicate keys in the Svelte sidebar each-block
(each_key_duplicate error). Adding Chat.id as a tiebreaker ensures
fully deterministic ordering.

Extends the fix from #22383 (which addressed get_chat_ids_by_model_id)
to all remaining paginated chat queries.
This commit is contained in:
Classic298
2026-03-08 03:16:50 +01:00
committed by GitHub
parent d0c3180376
commit 223c14f48b

View File

@@ -734,13 +734,13 @@ class ChatTable:
raise ValueError("Invalid order_by field")
if direction.lower() == "asc":
query = query.order_by(getattr(Chat, order_by).asc())
query = query.order_by(getattr(Chat, order_by).asc(), Chat.id)
elif direction.lower() == "desc":
query = query.order_by(getattr(Chat, order_by).desc())
query = query.order_by(getattr(Chat, order_by).desc(), Chat.id)
else:
raise ValueError("Invalid direction for ordering")
else:
query = query.order_by(Chat.updated_at.desc())
query = query.order_by(Chat.updated_at.desc(), Chat.id)
query = query.with_entities(
Chat.id, Chat.title, Chat.updated_at, Chat.created_at
@@ -793,13 +793,13 @@ class ChatTable:
raise ValueError("Invalid order_by field")
if direction.lower() == "asc":
query = query.order_by(getattr(Chat, order_by).asc())
query = query.order_by(getattr(Chat, order_by).asc(), Chat.id)
elif direction.lower() == "desc":
query = query.order_by(getattr(Chat, order_by).desc())
query = query.order_by(getattr(Chat, order_by).desc(), Chat.id)
else:
raise ValueError("Invalid direction for ordering")
else:
query = query.order_by(Chat.updated_at.desc())
query = query.order_by(Chat.updated_at.desc(), Chat.id)
# Select only the columns needed for SharedChatResponse
# to avoid loading the heavy chat JSON blob
@@ -854,13 +854,13 @@ class ChatTable:
if order_by and direction and getattr(Chat, order_by):
if direction.lower() == "asc":
query = query.order_by(getattr(Chat, order_by).asc())
query = query.order_by(getattr(Chat, order_by).asc(), Chat.id)
elif direction.lower() == "desc":
query = query.order_by(getattr(Chat, order_by).desc())
query = query.order_by(getattr(Chat, order_by).desc(), Chat.id)
else:
raise ValueError("Invalid direction for ordering")
else:
query = query.order_by(Chat.updated_at.desc())
query = query.order_by(Chat.updated_at.desc(), Chat.id)
if skip:
query = query.offset(skip)
@@ -892,7 +892,7 @@ class ChatTable:
if not include_archived:
query = query.filter_by(archived=False)
query = query.order_by(Chat.updated_at.desc()).with_entities(
query = query.order_by(Chat.updated_at.desc(), Chat.id).with_entities(
Chat.id, Chat.title, Chat.updated_at, Chat.created_at
)
@@ -1039,14 +1039,14 @@ class ChatTable:
if order_by and direction:
if hasattr(Chat, order_by):
if direction.lower() == "asc":
query = query.order_by(getattr(Chat, order_by).asc())
query = query.order_by(getattr(Chat, order_by).asc(), Chat.id)
elif direction.lower() == "desc":
query = query.order_by(getattr(Chat, order_by).desc())
query = query.order_by(getattr(Chat, order_by).desc(), Chat.id)
else:
query = query.order_by(Chat.updated_at.desc())
query = query.order_by(Chat.updated_at.desc(), Chat.id)
else:
query = query.order_by(Chat.updated_at.desc())
query = query.order_by(Chat.updated_at.desc(), Chat.id)
total = query.count()
@@ -1188,7 +1188,7 @@ class ChatTable:
if folder_ids:
query = query.filter(Chat.folder_id.in_(folder_ids))
query = query.order_by(Chat.updated_at.desc())
query = query.order_by(Chat.updated_at.desc(), Chat.id)
# Check if the database dialect is either 'sqlite' or 'postgresql'
dialect_name = db.bind.dialect.name
@@ -1309,7 +1309,7 @@ class ChatTable:
query = query.filter(or_(Chat.pinned == False, Chat.pinned == None))
query = query.filter_by(archived=False)
query = query.order_by(Chat.updated_at.desc())
query = query.order_by(Chat.updated_at.desc(), Chat.id)
if skip:
query = query.offset(skip)