666ghj/MiroFish · error · TimeoutError
Zep episode processing timed out with {len(pending_episodes)
Error message
Zep episode processing timed out with {len(pending_episodes)} episode(s) still pending What it means
Raised by GraphBuilder._wait_for_episodes when polling client.graph.episode.get(uuid_=...) shows episodes still not processed (episode.processed is falsy) after the timeout window. After a batch upload, Zep asynchronously processes each episode into graph entities/edges; this loop blocks until all episode_uuids report processed=True or the deadline (default derived from ZEP_INGESTION_WAIT_TIMEOUT_SECONDS = 600s) expires, then raises TimeoutError.
Source
Thrown at backend/app/services/graph_builder.py:747
progress_callback(t('progress.noEpisodesWait'), 1.0)
return
start_time = time.time()
pending_episodes = set(episode_uuids)
completed_count = 0
total_episodes = len(episode_uuids)
if progress_callback:
progress_callback(t('progress.waitingEpisodes', count=total_episodes), 0)
while pending_episodes:
if time.time() - start_time > timeout:
if progress_callback:
progress_callback(
t('progress.episodesTimeout', completed=completed_count, total=total_episodes),
completed_count / total_episodes
)
raise TimeoutError(
f"Zep episode processing timed out with "
f"{len(pending_episodes)} episode(s) still pending"
)
# 检查每个 episode 的处理状态
for ep_uuid in list(pending_episodes):
episode = call_zep_read_with_retry(
lambda: self.client.graph.episode.get(uuid_=ep_uuid),
operation_name=f"poll episode {ep_uuid}",
)
is_processed = getattr(episode, 'processed', False)
if is_processed:
pending_episodes.remove(ep_uuid)
completed_count += 1
elapsed = int(time.time() - start_time)
if progress_callback:View on GitHub (pinned to b5b53acc57)
Solutions
- Increase the episode wait timeout proportional to episode count (graph extraction is far slower than batch acceptance).
- Re-poll the pending episodes after the timeout — most complete shortly after; only treat permanently unprocessed episodes as failures.
- Ingest in smaller batches so the per-batch episode queue stays shallow.
- If specific episode UUIDs stay unprocessed for hours, escalate to Zep support with the UUIDs.
Example fix
# before builder._wait_for_episodes(episode_uuids, timeout=600) # after timeout = max(600, 30 * len(episode_uuids)) builder._wait_for_episodes(episode_uuids, timeout=timeout)
Defensive patterns
Strategy: retry
Validate before calling
timeout = max(600, 30 * len(episode_uuids)) # graph extraction is slower than batch acceptance
Try / catch
try:
builder._wait_for_episodes(episode_uuids, timeout=timeout)
except TimeoutError:
still_pending = [u for u in episode_uuids if poll_later(u)]
if still_pending:
escalate(still_pending)
# else: all completed shortly after the deadline; continue Prevention
- Scale the episode wait with the number of episodes.
- Ingest in smaller batches so graph extraction keeps up.
- Treat the first timeout as a signal to re-poll, not to fail the run.
When it happens
Trigger: Many episodes queued for graph processing at once (large batch succeeded, graph extraction backlog exceeds the wait window); Zep cloud under load; a few episodes stuck unprocessed indefinitely on Zep's side; timeout passed too small by the caller.
Common situations: Ingesting hundreds of chunks in one go and immediately waiting for graph readiness; peak-hour Zep latency; following a batch that 'succeeded' quickly but whose graph extraction is slow.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Zep batch {submission.batch_id} did not finish within {timeo
- Zep simulation ingestion timed out with {len(pending)} episo
- episode {episode_uuid} did not finish within {timeout}s
- 模拟仍在停止中,图谱写入未在 {wait_timeout:.0f}s 内完成
- Zep updater worker did not stop within {join_timeout:.0f}s
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/5527212a8a0bd808.
Report an issue: GitHub.