{"record":{"id":"b5b7aa710ea1ef35","repo":"666ghj/MiroFish","slug":"batch-item-cursor-did-not-advance","errorCode":null,"errorMessage":"batch item cursor did not advance","messagePattern":"batch item cursor did not advance","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"backend/scripts/validate_zep_cloud_integration.py","lineNumber":313,"sourceCode":"        if getattr(episode, \"processed\", False):\n            return episode\n        time.sleep(3)\n    raise TimeoutError(f\"episode {episode_uuid} did not finish within {timeout}s\")\n\n\ndef _list_batch_items(client: Any, batch_id: str, page_size: int = 3) -> tuple[list[Any], int]:\n    items: list[Any] = []\n    cursor: int | None = None\n    pages = 0\n    while True:\n        response = client.batch.list_items(batch_id=batch_id, limit=page_size, cursor=cursor)\n        pages += 1\n        items.extend(response.items or [])\n        next_cursor = response.next_cursor\n        if next_cursor is None:\n            return items, pages\n        if next_cursor == cursor:\n            raise RuntimeError(\"batch item cursor did not advance\")\n        cursor = next_cursor\n\n\ndef _raw_pages(api_call: Any, graph_id: str, page_size: int = 2) -> tuple[list[Any], int]:\n    items: list[Any] = []\n    cursor: str | None = None\n    pages = 0\n    seen: set[str] = set()\n    while True:\n        kwargs: dict[str, Any] = {\"limit\": page_size}\n        if cursor:\n            kwargs[\"cursor\"] = cursor\n        response = api_call(graph_id, **kwargs)\n        pages += 1\n        items.extend(list(response.data or []))\n        next_cursor = response.headers.get(\"zep-next-cursor\")\n        if not next_cursor:\n            return items, pages","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/backend/scripts/validate_zep_cloud_integration.py#L295-L331","documentation":"Raised by _list_batch_items in backend/scripts/validate_zep_cloud_integration.py when client.batch.list_items returns a next_cursor equal to the cursor used for the current page — meaning pagination would fetch the same page forever. Note this guard only compares next_cursor == cursor (an int cursor with None start), not a full seen-set. It is a RuntimeError raised mid-pagination.","triggerScenarios":"Listing a batch's items when the API repeats the same cursor — a batch still settling right after client.batch.process, a server-side cursor bug, or an SDK version mis-reading next_cursor.","commonSituations":"Polling list_items immediately after process() while the backend still mutates the listing; zep-cloud SDK upgrade changing cursor semantics; rare Zep Cloud API regression.","solutions":["Retry the listing after a short wait — transient repetition right after batch.process usually resolves once the batch settles.","Upgrade the zep-cloud package to the latest release.","If reproducible, capture batch_id and both cursor values and report to Zep support; use the console batch view to inspect items meanwhile."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        items, pages = _list_batch_items(client, batch_id, page_size=3)\n        break\n    except RuntimeError as e:\n        if \"cursor did not advance\" not in str(e) or attempt == 2:\n            raise\n        time.sleep(5)","preventionTips":["Let batches settle after process() before listing items repeatedly.","Pin and periodically re-verify the zep-cloud SDK version used by validation scripts.","Treat repeated cursor stalls as an API incident signal — capture evidence and report."],"tags":["zep","pagination","batch-api","infinite-loop-guard","runtime"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}