PrefectHQ/fastmcp · error · HorizonResponseError

Horizon returned an invalid organization cursor

Error message

Horizon returned an invalid organization cursor

What it means

HorizonResponseError raised when the paginated organization listing from the Horizon API returns a nextCursor that was already seen. This indicates the server's cursor pagination is looping instead of advancing, so continuing would iterate forever. The library guards against this infinite-loop condition and aborts with the HTTP status code of the failing response.

Source

Thrown at fastmcp_slim/fastmcp/cli/deploy/horizon_client.py:320

        while True:
            params = {"limit": 100}
            if cursor is not None:
                params["cursor"] = cursor
            response = await self._request(
                "GET",
                "/api/v0/me/organizations",
                authenticated=True,
                params=params,
            )
            self._require_status(response, 200)
            result = self._validate_response(response, _OrganizationsResponse)
            organizations.extend(result.items)

            cursor = result.meta.nextCursor
            if cursor is None:
                return tuple(organizations)
            if cursor in seen_cursors:
                raise HorizonResponseError(
                    "Horizon returned an invalid organization cursor",
                    status_code=response.status_code,
                )
            seen_cursors.add(cursor)

    async def revoke_current_api_key(self) -> None:
        response = await self._request(
            "DELETE",
            "/api/v0/me/api-key",
            authenticated=True,
        )
        self._require_status(response, 204)

View on GitHub (pinned to 1f02114297)

Solutions

  1. Retry the call after a short delay — a transient Horizon fault may have produced the looping page
  2. Verify the Horizon server version is current; report the looping-cursor bug to the server operator if it persists
  3. Check for proxies/caches between the client and Horizon that could replay a cached page
  4. Capture the status_code and cursors observed and file an issue with fastmcp
Defensive patterns

Strategy: retry

Try / catch

from fastmcp.cli.deploy.horizon_client import HorizonResponseError

for attempt in range(3):
    try:
        orgs = await client.list_organizations()
        break
    except HorizonResponseError as exc:
        if attempt == 2:
            logger.error("Horizon pagination looped (status %s)", exc.status_code)
            raise
        await asyncio.sleep(2 ** attempt)

Prevention

When it happens

Trigger: Calling list_organizations() when the Horizon server returns a pagination chain whose meta.nextCursor repeats a previously returned cursor (a cycle), instead of eventually returning None.

Common situations: A Horizon backend bug or upgrade regression in cursor generation; a broken/misconfigured Horizon deployment replaying the same page; proxy caching returning a stale page for each cursor; a corrupted or duplicated cursor value in server metadata.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/296c83def832a55a. Report an issue: GitHub.