Comfy-Org/ComfyUI · error · InvalidCursorError
INVALID_CURSOR
INVALID_CURSOR
Error message
cursor pagination is not supported for sort={sort!r} What it means
InvalidCursorError raised by the listing service when a request supplies an `after` cursor while `sort` is not one of the cursor-supported fields (created_at, updated_at, name, size). The service only enters cursor mode for those sorts; other sort orders use offset pagination and cannot interpret a cursor.
Source
Thrown at app/assets/services/asset_management.py:301
any_tags: Sequence[str] | None = None,
) -> ListAssetsResult:
"""List assets with optional cursor pagination.
When ``after`` is supplied it overrides ``offset``. The cursor's sort field
must match ``sort`` and be in the cursor-supported allowlist; mismatches
raise InvalidCursorError so the handler can map to 400 INVALID_CURSOR.
"""
cursor_value: object | None = None
cursor_id: str | None = None
# Mint next_cursor on every page where the sort is cursor-supported, not
# only when the request itself arrived with a cursor. Otherwise a first
# request (no `after`) returns next_cursor=None and the client can never
# enter cursor mode.
mint_cursor = sort in _CURSOR_SORT_FIELDS
if after is not None:
if sort not in _CURSOR_SORT_FIELDS:
raise InvalidCursorError(
f"cursor pagination is not supported for sort={sort!r}"
)
payload = decode_cursor(after, _CURSOR_SORT_FIELDS, expected_order=order)
if payload.sort_field != sort:
raise InvalidCursorError(
f"cursor sort field {payload.sort_field!r} does not match request sort {sort!r}"
)
cursor_value, cursor_id = _resolve_cursor_value(payload), payload.id
# Over-fetch by one row so we can distinguish "exactly `limit` rows total
# remaining" from "more rows past this page" without a second query. Drop
# the sentinel before returning.
fetch_limit = limit + 1 if mint_cursor else limit
with create_session() as session:
refs, tag_map, total = list_references_page(
session,
owner_id=owner_id,View on GitHub (pinned to 1c6d8d45b3)
Solutions
- Drop the after parameter when requesting a non-cursor-supported sort.
- Keep the sort stable across pages: reuse the exact sort that minted the cursor.
- If a new sort must support cursors, add the field to _CURSOR_SORT_FIELDS and implement its keyset comparison.
- Catch InvalidCursorError and return 400 INVALID_CURSOR so the client can reset to page one.
Example fix
# before
list_assets(sort="random", after=next_cursor)
# after
CURSOR_SORTS = {"created_at", "updated_at", "name", "size"}
list_assets(sort="random", after=next_cursor if sort in CURSOR_SORTS else None) Defensive patterns
Strategy: validation
Validate before calling
CURSOR_SORTS = {"created_at", "updated_at", "name", "size"}
def safe_after(sort: str, after: str | None) -> str | None:
return after if (after and sort in CURSOR_SORTS) else None Try / catch
try:
page = list_assets(sort=sort, after=after)
except InvalidCursorError as e:
# 400: reset pagination
page = list_assets(sort=sort, after=None) Prevention
- Clear the after token whenever the sort control changes.
- Only send cursors for the four supported sorts; use offset pagination otherwise.
- On 400 INVALID_CURSOR, restart from page one.
When it happens
Trigger: Calling the list endpoint with both after=<cursor> and a sort value outside ('created_at','updated_at','name','size'), e.g. sort=random or a custom sort, with a next_cursor carried over from a previous page.
Common situations: Client changes the sort control mid-pagination but keeps the after parameter; a new sort option added server-side without extending _CURSOR_SORT_FIELDS; saved/bookmarked URLs that embed an old cursor being replayed with a different sort.
Related errors
AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14).
Data as JSON: /api/errors/fd2e19eae5286c51.
Report an issue: GitHub.