666ghj/MiroFish · error · RuntimeError
Zep batch {batch_id} item cursor did not advance
Error message
Zep batch {batch_id} item cursor did not advance What it means
Raised inside GraphBuilder._list_batch_items while paginating Zep batch items with client.batch.list_items(limit=100, cursor=...). The loop terminates when next_cursor is None; if the API ever returns a cursor equal to the current one or one already visited (seen_cursors), it raises RuntimeError to prevent an infinite pagination loop. This indicates a server-side pagination anomaly or an SDK/API version mismatch rather than a problem with the submitted data.
Source
Thrown at backend/app/services/graph_builder.py:600
def _list_batch_items(self, batch_id: str) -> List[Any]:
items: List[Any] = []
cursor: int | None = None
seen_cursors: set[int] = set()
while True:
page = call_zep_read_with_retry(
lambda: self.client.batch.list_items(
batch_id=batch_id,
limit=100,
cursor=cursor,
),
operation_name=f"list batch items {batch_id}",
)
items.extend(getattr(page, "items", None) or [])
next_cursor = getattr(page, "next_cursor", None)
if next_cursor is None:
break
if next_cursor == cursor or next_cursor in seen_cursors:
raise RuntimeError(f"Zep batch {batch_id} item cursor did not advance")
seen_cursors.add(next_cursor)
cursor = next_cursor
return items
def _reconcile_batch_item_count(
self,
batch_id: str,
expected_item_count: int,
*,
max_attempts: int = 3,
) -> List[Any]:
"""Allow a short propagation window after an ambiguous add reply."""
items: List[Any] = []
for attempt in range(1, max_attempts + 1):
items = self._list_batch_items(batch_id)
if len(items) >= expected_item_count:
return itemsView on GitHub (pinned to b5b53acc57)
Solutions
- Retry the whole read after a short wait (30-60s) — transient cursor instability right after batch completion usually resolves.
- Check the zep-cloud SDK version against Zep's current docs and upgrade if it is behind; cursor semantics changed across versions.
- If persistent, capture batch_id, page cursors and open a Zep support ticket — a never-advancing cursor is a service defect.
- As a defensive workaround in your own fork, re-issue list_items from scratch instead of trusting the repeated cursor.
Example fix
// before
items = self._list_batch_items(batch_id)
# after
for attempt in range(3):
try:
items = self._list_batch_items(batch_id)
break
except RuntimeError as e:
if 'cursor did not advance' not in str(e) or attempt == 2:
raise
time.sleep(30) Defensive patterns
Strategy: retry
Try / catch
for attempt in range(3):
try:
items = builder._list_batch_items(batch_id)
break
except RuntimeError as e:
if 'cursor did not advance' not in str(e):
raise
if attempt == 2:
raise
time.sleep(30) # give Zep's cursor time to stabilize Prevention
- Pin a current zep-cloud SDK version and upgrade deliberately.
- Avoid listing very large batches in the instant after completion; wait a few seconds.
- Log cursors per page so a repeating cursor is diagnosable from history.
When it happens
Trigger: Calling _list_batch_items on a batch with more than 100 items (multiple pages), where Zep returns a next_cursor that repeats a previously seen value. Can also happen if the batch's items are still being written and list_items returns an unstable cursor, or when a pinned zep-cloud SDK version speaks an older cursor contract than the server.
Common situations: Large batches (hundreds/thousands of items) read immediately after batch completion; Zep service-side pagination regressions; upgrading or downgrading the zep-cloud SDK without regenerating cursor handling; rarely, clock/inconsistency windows during eventual consistency.
Related errors
- batch item cursor did not advance
- Zep batch list cursor did not advance
- Zep batch {submission.batch_id} contains {len(items)} items,
- Zep {item_name} pagination cursor did not advance for graph
- artifact cursor did not advance
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/bbf3ac17f13e307b.
Report an issue: GitHub.