Comfy-Org/ComfyUI · error · InvalidCursorError
INVALID_CURSOR
INVALID_CURSOR
Error message
cursor exceeds maximum length
What it means
InvalidCursorError raised at the top of decode_cursor when the encoded cursor string exceeds MAX_ENCODED_CURSOR_LENGTH (8192 characters). The length cap is a cheap first line of defense before any base64/JSON parsing, bounding payload size before decode work is done.
Source
Thrown at app/assets/services/cursor.py:127
cursor: str,
allowed_sort_fields: Iterable[str],
expected_order: str | None = None,
) -> CursorPayload:
"""Parse an opaque cursor.
``allowed_sort_fields`` is the endpoint's accepted sort-field list — a
cursor carrying a field outside this set is rejected so a cursor minted
for one column can't be replayed against another (e.g. a ``created_at``
timestamp string compared against a ``name`` column).
``expected_order`` (``"asc"``/``"desc"``), when supplied, must match the
payload's ``o`` field. ``o`` is required on every payload; a cursor
missing it is rejected as malformed.
Passing no allowed fields rejects every cursor.
"""
if len(cursor) > MAX_ENCODED_CURSOR_LENGTH:
raise InvalidCursorError("cursor exceeds maximum length")
try:
# urlsafe_b64decode requires correct padding; we strip on encode, so
# restore the trailing '=' pad here.
padding = "=" * (-len(cursor) % 4)
raw = base64.urlsafe_b64decode(cursor + padding)
except (ValueError, base64.binascii.Error) as e:
raise InvalidCursorError(f"encoding: {e}") from e
try:
decoded = json.loads(raw)
except (json.JSONDecodeError, UnicodeDecodeError) as e:
raise InvalidCursorError(f"payload: {e}") from e
if not isinstance(decoded, dict):
raise InvalidCursorError("payload: expected object")
sort_field = decoded.get("s")View on GitHub (pinned to 1c6d8d45b3)
Solutions
- Check len(cursor) <= 8192 client-side before sending and treat oversized values as session-reset.
- Verify you are passing exactly the next_cursor string from the prior response, unmodified and URL-encoded once.
- Reset pagination and fetch page one when an oversized/invalid cursor is detected.
- Return 400 INVALID_CURSOR rather than retrying the same token.
Example fix
# before
resp = list_assets(after=params.get("after", ""))
# after
raw = params.get("after", "")
after = raw if raw and len(raw) <= 8192 else None
resp = list_assets(after=after) Defensive patterns
Strategy: validation
Validate before calling
MAX_LEN = 8192
def usable_cursor(raw: str | None) -> str | None:
return raw if raw and len(raw) <= MAX_LEN else None Try / catch
try:
page = list_assets(after=after)
except InvalidCursorError:
page = list_assets() # reset to page one Prevention
- Send next_cursor verbatim and URL-encode it exactly once.
- Length-check tokens client-side and reset pagination when they look wrong.
- Never paste unrelated data into the after parameter.
When it happens
Trigger: Sending an after parameter longer than 8192 chars — typically not a real cursor but accidentally attached data: a full URL, a JSON blob, a pasted token, or a proxy/gateway appending junk to query parameters.
Common situations: Query-string corruption by middlewares or hand-built URLs; clients copying an entire response body into the after field; a copied URL whose cursor param got duplicated repeatedly by a buggy link builder.
Related errors
AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14).
Data as JSON: /api/errors/25f72faa67a2c1a9.
Report an issue: GitHub.