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
- Retry the call after a short delay — a transient Horizon fault may have produced the looping page
- Verify the Horizon server version is current; report the looping-cursor bug to the server operator if it persists
- Check for proxies/caches between the client and Horizon that could replay a cached page
- 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
- Keep the Horizon server and fastmcp client versions in sync
- Avoid caching proxies between the client and Horizon for authenticated API routes
- Log the observed cursor chain to make server-side pagination bugs reproducible
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
- Unexpected authorization response: {response.status_code}
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/296c83def832a55a.
Report an issue: GitHub.