bytedance/deer-flow · error · HTTPException

Could not find source run for assistant message

Error message

Could not find source run for assistant message

What it means

Raised in _find_target_run_id (HTTP 409) when no run record can be linked to the assistant message being regenerated: neither the journal lookup nor the fallback scan (recent run events, bounded by REGENERATE_HISTORY_SCAN_LIMIT = 200) found a successful run whose last AI message matches. The server needs the source run_id to rerun the turn, so regenerate is refused.

Source

Thrown at backend/app/gateway/routers/thread_runs.py:515

        return source_run_id

    run_mgr = get_run_manager(request)
    user_id = await get_current_user(request)
    records = await run_mgr.list_by_thread(thread_id, user_id=user_id, limit=10)
    fallback_record = next(
        (record for record in records if record.status == RunStatus.success and _run_last_ai_matches_message(record, target_message)),
        None,
    )
    if fallback_record is not None:
        return fallback_record.run_id
    if len(rows) >= REGENERATE_HISTORY_SCAN_LIMIT:
        logger.warning(
            "Could not find source run for regenerate message %s in recent run events for thread %s (limit=%s)",
            message_id,
            thread_id,
            REGENERATE_HISTORY_SCAN_LIMIT,
        )
    raise HTTPException(status_code=409, detail="Could not find source run for assistant message")


async def _find_base_checkpoint_before_human(
    thread_id: str,
    human_message_id: str,
    request: Request,
    *,
    head_checkpoint: Any | None = None,
) -> Any:
    accessor, base_config = await build_thread_checkpoint_state_accessor(request, thread_id=thread_id)
    if head_checkpoint is not None:
        try:
            return await find_checkpoint_before_message(
                accessor,
                head_checkpoint,
                human_message_id,
                max_depth=REGENERATE_HISTORY_RAW_SCAN_LIMIT,
            )

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Regenerate the latest turn first (its run events are freshest) instead of reaching far back in history.
  2. Check run-event journal retention settings and the run manager store backend; ensure runs are persisted, not in-memory only.
  3. Increase REGENERATE_HISTORY_SCAN_LIMIT if the deployment regularly exceeds 200 run events between turns.
  4. As a workaround, start a new thread and resurface needed context rather than regenerating a very old turn.
Defensive patterns

Strategy: fallback

Validate before calling

const runs = await listRuns(threadId, {status: 'success'});
if (!runs.some(r => r.final_message_id === targetMessageId)) {
  // regenerate the latest turn instead, or start a new thread
}

Try / catch

try { await regeneratePrepare(threadId, messageId); } catch (e) { if (e.status === 409 && /source run/.test(e.detail)) { await resyncThreadAndRegenerateLatest(threadId); } else throw e; }

Prevention

When it happens

Trigger: Regenerating an assistant message whose producing run's event journal was trimmed beyond the 200-entry scan limit; run store persistence gap where run records were never hydrated; regenerating an old turn after 200+ newer events.

Common situations: Long threads with heavy tool activity that floods run events; restarting the Gateway with an in-memory run store so older run records were lost; run-event journal retention/pruning configured aggressively.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/48703e1b337f0bdd. Report an issue: GitHub.