666ghj/MiroFish · error · RuntimeError

Zep Batch API returned no batch_id

Error message

Zep Batch API returned no batch_id

What it means

RuntimeError in submit_document_batch: a batch object came back from create (or from reconcile) but getattr(batch, 'batch_id', None) is empty — the Zep Batch API response lacks the batch identifier this code depends on for every subsequent call (add items, process, get). Without a batch_id the operation cannot proceed and, importantly, the batch_created_callback(batch_id, ...) journaling would persist a useless identity, so it aborts first.

Source

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

        try:
            batch = self.client.batch.create(
                metadata={
                    "mirofish_operation_id": operation_id,
                    "graph_id": graph_id,
                    "chunk_count": total_chunks,
                }
            )
        except Exception as error:
            if not is_retryable_zep_error(error):
                raise
            batch = self._find_batch_by_operation_id(graph_id, operation_id)
            if batch is None:
                raise RuntimeError(
                    "Zep batch creation is unconfirmed and no matching operation was found"
                ) from error
        batch_id = getattr(batch, "batch_id", None)
        if not batch_id:
            raise RuntimeError("Zep Batch API returned no batch_id")
        if batch_created_callback:
            batch_created_callback(batch_id, operation_id)

        episode_uuids: List[str] = []
        for i in range(0, total_chunks, batch_size):
            batch_chunks = chunks[i:i + batch_size]
            batch_num = i // batch_size + 1
            total_batches = (total_chunks + batch_size - 1) // batch_size
            
            if progress_callback:
                progress = (i + len(batch_chunks)) / total_chunks
                progress_callback(
                    t('progress.sendingBatch', current=batch_num, total=total_batches, chunks=len(batch_chunks)),
                    progress
                )
            
            items = [
                BatchAddItem(

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Log the full batch object when this fires to see the actual response shape.
  2. Pin or upgrade the Zep SDK to the version this service was written against, and re-check the batch-create response schema.
  3. If the field was renamed, read it with a fallback: batch_id = getattr(batch, 'batch_id', None) or getattr(batch, 'id', None).
  4. Because the batch may exist server-side, look it up by mirofish_operation_id in the Zep console and clean up or resume manually.
  5. In tests, make mocked batches include a realistic batch_id.

Example fix

# before
batch_id = getattr(batch, "batch_id", None)
if not batch_id:
    raise RuntimeError("Zep Batch API returned no batch_id")

# after - tolerate schema rename, keep the hard failure for true emptiness
batch_id = (
    getattr(batch, "batch_id", None)
    or getattr(batch, "id", None)
)
if not batch_id:
    raise RuntimeError(
        f"Zep Batch API returned no batch_id (response type={type(batch).__name__}, "
        f"fields={getattr(batch, 'model_fields', None) or vars(getattr(batch, '__dict__', {}))}"
    )
Defensive patterns

Strategy: type-guard

Type guard

def has_batch_id(batch) -> bool:
    return bool(getattr(batch, 'batch_id', None) or getattr(batch, 'id', None))

Try / catch

try:
    submission = builder.submit_document_batch(graph_id, chunks, batch_size=bs)
except RuntimeError as e:
    if 'no batch_id' in str(e):
        # batch may exist server-side; find it by mirofish_operation_id before any retry
        logger.error('Batch create returned no id; reconcile by operation metadata: %s', str(e))
        raise
    raise

Prevention

When it happens

Trigger: Zep SDK version change renaming the field (e.g. id instead of batch_id) so getattr misses it; a degenerate response object (empty model) returned during a partial outage; the reconcile path matched a batch stub without an id.

Common situations: Upgrading the zep-python SDK to a version with a different response schema; server error pages deserialized into empty objects; mocking in tests that returns a batch without batch_id.

Related errors


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