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

  1. Check len(cursor) <= 8192 client-side before sending and treat oversized values as session-reset.
  2. Verify you are passing exactly the next_cursor string from the prior response, unmodified and URL-encoded once.
  3. Reset pagination and fetch page one when an oversized/invalid cursor is detected.
  4. 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

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.