{"record":{"id":"1ccf505cfaac4542","repo":"666ghj/MiroFish","slug":"zep-batch-batch-id-item-submission-is-unconfirme","errorCode":null,"errorMessage":"Zep batch {batch_id} item submission is unconfirmed; the draft was not processed or replayed","messagePattern":"Zep batch (.+?) item submission is unconfirmed; the draft was not processed or replayed","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"backend/app/services/graph_builder.py","lineNumber":512,"sourceCode":"            except Exception as e:\n                if progress_callback:\n                    progress_callback(t('progress.batchFailed', batch=batch_num, error=str(e)), 0)\n                if is_retryable_zep_error(e):\n                    recovered_items = self._reconcile_batch_item_count(\n                        batch_id,\n                        expected_item_count,\n                    )\n                    recovered_indexes = {\n                        getattr(item, \"sequence_index\", None)\n                        for item in recovered_items\n                    }\n                    if (\n                        len(recovered_items) == expected_item_count\n                        and recovered_indexes == set(range(expected_item_count))\n                    ):\n                        item_details = recovered_items[i:expected_item_count]\n                    else:\n                        raise RuntimeError(\n                            f\"Zep batch {batch_id} item submission is unconfirmed; \"\n                            \"the draft was not processed or replayed\"\n                        ) from e\n                else:\n                    raise RuntimeError(\n                        f\"Zep batch {batch_id} item submission failed\"\n                    ) from e\n\n            if len(item_details or []) != len(items):\n                recovered_items = self._reconcile_batch_item_count(\n                    batch_id,\n                    expected_item_count,\n                )\n                recovered_indexes = {\n                    getattr(item, \"sequence_index\", None)\n                    for item in recovered_items\n                }\n                if (","sourceCodeStart":494,"sourceCodeEnd":530,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/backend/app/services/graph_builder.py#L494-L530","documentation":"RuntimeError in submit_document_batch's item-add loop: client.batch.add failed with a retryable error, so the code reconciled by listing the batch's items and checking that the recovered set is exactly expected_item_count items with sequence_index covering range(expected_item_count). If the recovered items are incomplete or out of sequence, the draft was neither fully processed nor safely replayable, so continuing risks duplicated or missing episodes — it refuses.","triggerScenarios":"A timeout/429/503 partway through batch.add for a chunk group; Zep accepted only some items before the connection broke; the reconcile listing itself is eventually consistent and shows fewer items than were actually accepted.","commonSituations":"Long builds (thousands of chunks) where a single flaky request out of hundreds triggers recovery; mobile/unstable server networking; Zep Cloud degraded performance making both add and list slow.","solutions":["Retry the whole build resume flow: the persisted zep_batch_id/operation_id lets the API layer resume the existing batch instead of creating a new one.","Before retrying, inspect the batch in the Zep console: if items are partially present, either wait for listing consistency or delete the draft batch and restart cleanly.","Reduce batch_size (max 350) or chunk counts per submission to shrink the failure window.","Increase reconcile patience (retries/backoff in _reconcile_batch_item_count) if Zep's item listing lags.","Check the chained cause error to confirm it was genuinely retryable and not a misclassified auth error."],"exampleFix":"# before\nelse:\n    raise RuntimeError(\n        f\"Zep batch {batch_id} item submission is unconfirmed; the draft was not processed or replayed\"\n    ) from e\n\n# after - retry reconciliation once after a short delay before refusing\nelse:\n    time.sleep(2)\n    recovered_items = self._reconcile_batch_item_count(batch_id, expected_item_count)\n    recovered_indexes = {getattr(item, \"sequence_index\", None) for item in recovered_items}\n    if len(recovered_items) == expected_item_count and recovered_indexes == set(range(expected_item_count)):\n        item_details = recovered_items[i:expected_item_count]\n    else:\n        raise RuntimeError(\n            f\"Zep batch {batch_id} item submission is unconfirmed \"\n            f\"(recovered {len(recovered_items)}/{expected_item_count}); \"\n            \"the draft was not processed or replayed\"\n        ) from e","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    submission = builder.submit_document_batch(graph_id, chunks, batch_size=bs)\nexcept RuntimeError as e:\n    if 'item submission is unconfirmed' in str(e):\n        # persisted zep_batch_id/operation_id allow the resume path to reconcile later\n        logger.warning('Batch item add unconfirmed for %s; retry via resume', project.zep_batch_id)\n        raise RetriableBuildError(str(e)) from e\n    raise","preventionTips":["Persist batch identity immediately via batch_created_callback so any failure is resumable.","Keep batch_size modest to shrink the per-add failure window.","Verify Zep item listing is consistent (reconcile counts twice) before declaring unrecoverable.","Run builds with retry/backoff at the orchestration layer keyed on 'unconfirmed' errors."],"tags":["backend","python","zep","batch","partial-failure","recovery"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}