666ghj/MiroFish · error · RuntimeError

Zep batch list cursor did not advance

Error message

Zep batch list cursor did not advance

What it means

RuntimeError in _find_batch_by_operation_id (graph_builder.py): while paginating Zep's batch list to reconcile a possibly-lost batch-create response, the returned next_cursor either equals the current cursor or a previously seen one. The service treats a non-advancing cursor as a protocol violation and aborts instead of looping forever, because continuing would re-scan the same page and could append duplicate matches.

Source

Thrown at backend/app/services/graph_builder.py:299

            cursor: int | None = None
            seen_cursors: set[int] = set()
            while True:
                page = call_zep_read_with_retry(
                    lambda: self.client.batch.list(limit=100, cursor=cursor),
                    operation_name=f"reconcile batch create {operation_id}",
                )
                for batch in getattr(page, "batches", None) or []:
                    metadata = getattr(batch, "metadata", None) or {}
                    if (
                        metadata.get("mirofish_operation_id") == operation_id
                        and metadata.get("graph_id") == graph_id
                    ):
                        matches.append(batch)
                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("Zep batch list cursor did not advance")
                seen_cursors.add(next_cursor)
                cursor = next_cursor

            if len(matches) > 1:
                raise RuntimeError(
                    f"Multiple Zep batches match operation {operation_id}; refusing ambiguity"
                )
            if matches:
                return matches[0]
            if attempt < max_attempts:
                time.sleep(attempt)
        return None
    
    def set_ontology(self, graph_id: str, ontology: Dict[str, Any]):
        """设置图谱本体(公开方法)"""
        import warnings
        from typing import Optional
        from pydantic import Field

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Retry the operation — transient pagination glitches usually clear; the deterministic operation_id makes a retry of the whole reconcile safe.
  2. Upgrade (or pin) the Zep client SDK to a version whose list-batch pagination matches this code path.
  3. Inspect the raw page payloads (log next_cursor per iteration) to confirm whether the server or the client is repeating pages.
  4. If Zep consistently misbehaves, list all batches non-paginated (if supported) or filter server-side by metadata to avoid cursor logic.
  5. Check for caching proxies between the backend and Zep Cloud and exclude the batch endpoint.

Example fix

# before
if next_cursor == cursor or next_cursor in seen_cursors:
    raise RuntimeError("Zep batch list cursor did not advance")

# after - tolerate one repeat by re-requesting once, then fail with context
if next_cursor == cursor or next_cursor in seen_cursors:
    if not retried_this_page:
        retried_this_page = True
        continue  # one fresh request for the same cursor
    raise RuntimeError(
        f"Zep batch list cursor did not advance (cursor={cursor!r}, "
        f"seen={len(seen_cursors)} pages); aborting to avoid an infinite loop"
    )
Defensive patterns

Strategy: retry

Try / catch

try:
    batch = builder._find_batch_by_operation_id(graph_id, operation_id)
except RuntimeError as e:
    if 'cursor did not advance' in str(e):
        time.sleep(2)
        batch = builder._find_batch_by_operation_id(graph_id, operation_id)  # one bounded retry
    else:
        raise

Prevention

When it happens

Trigger: Zep Cloud's batch list endpoint returns the same next_cursor for consecutive pages (server bug or pagination quirk); a middleware/proxy caches the list response so every page looks identical; the page object shape changed so next_cursor parsing yields a stale value.

Common situations: Zep SDK/API version drift changing pagination semantics; large batch histories triggering cursor reuse; flaky network plus an aggressive retry layer replaying the same response.

Related errors


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/8fee9ca3c23c27b4. Report an issue: GitHub.