VFX-E-1506¶
Title¶
InvalidCursor
Explanation¶
A paginated tool was given a cursor it could not verify, so the page it points at could not be
served. Nothing was returned and nothing was skipped.
A cursor is an opaque continuation token. Tools that page their results return one as
nextCursor when more items remain; the only supported use of that value is to pass it straight
back, unchanged, as cursor on the next call. It is not a value to construct, parse, edit, or
carry between tools — its contents are this server's own business and may change without notice.
There are four ways verification fails, and the error message names which one happened:
- Malformed — the value is not a cursor this server issued: not the right encoding, truncated, padded, prefixed, or otherwise altered. A cursor carries an internal checksum specifically so a corrupted one is refused rather than silently decoded to a different position.
- A different build — the cursor was issued by a server whose cursor format has since changed.
- A different tool — cursors are single-purpose. One tool's
nextCursordoes not address another tool's results, even though both look like the same kind of string. - Different arguments — the cursor was issued under a different set of filters than the call now presenting it. A page walk's position only means anything under the filters that produced it.
That last case is the important one, and it is why this is an error rather than a silent restart from the first page. Serving page one instead would hand a caller a duplicate page dressed as a continuation; a host appending pages would quietly duplicate records with nothing to alert on. Refusing is the only answer that cannot corrupt the caller's own accumulation.
Note the asymmetry that follows from this: while paging, keep the filter arguments identical, but
limit may change freely between pages — a host that shrinks its page size mid-walk is not making
a mistake, and its cursor stays valid. The refusal message says so explicitly, so a host that hits
it after resizing its pages does not go hunting for the one argument that was never the cause.
Two tools page today and both use this one cursor implementation: get_run_events (bound to runId,
types and stepId) and list_runs (bound to label and since). Their cursors are
indistinguishable as strings and are deliberately not interchangeable — presenting one to the
other is the "different tool" case above, refused rather than decoded into a position that means
something entirely different.
Retrying the identical call cannot help — it carries the identical cursor — so this error is not retryable.
Common causes¶
- The
cursorwas edited, truncated, re-encoded, or reconstructed rather than passed back verbatim. - A filter argument changed between pages (for example
get_run_events'typesorstepId, orlist_runs'labelorsince), so the cursor no longer addresses the same result set. - A cursor from one tool was passed to another, or a cursor from one run was reused against a different run.
- A cursor was stored from an earlier session and replayed against a server built from a different version.
- A host built the argument object dynamically and sent an empty or whitespace
cursorwhere it meant to omit it entirely.
Fixes¶
- Pass back exactly the
nextCursorstring the same tool returned, with no modification. - Keep every filter argument identical for the whole page walk; only
limitmay vary between pages. - To start a new walk under new filters, omit
cursorentirely rather than reusing the old one. - Omit
cursorrather than sending an empty string when you mean "the first page". - Stop paging when
nextCursoris absent — its absence means there are no further matching items, so a further call is never needed.