bytedance/deer-flow · warning · HTTPException

Could not locate target user message in recent checkpoint hi

Error message

Could not locate target user message in recent checkpoint history (limit={REGENERATE_HISTORY_SCAN_LIMIT})

What it means

Raised in _find_base_checkpoint_before_human (HTTP 409) when the target user message id cannot be located anywhere in the scanned checkpoint history (bounded by REGENERATE_HISTORY_SCAN_LIMIT = 200 non-duration-only checkpoints). The chronological fallback could not even find the message, so no base checkpoint can be chosen.

Source

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

        raise HTTPException(status_code=500, detail="Failed to inspect checkpoint history") from exc

    previous_checkpoint, target_found = find_checkpoint_before_message_chronologically(raw_checkpoints, human_message_id)
    if target_found:
        if previous_checkpoint is None:
            raise HTTPException(
                status_code=409,
                detail=_MISSING_REGENERATE_BASE_DETAIL,
            )
        return previous_checkpoint

    if len(checkpoints) >= REGENERATE_HISTORY_SCAN_LIMIT:
        logger.warning(
            "Could not locate target user message %s in recent checkpoint history for thread %s (limit=%s)",
            human_message_id,
            thread_id,
            REGENERATE_HISTORY_SCAN_LIMIT,
        )
    raise HTTPException(
        status_code=409,
        detail=(f"Could not locate target user message in recent checkpoint history (limit={REGENERATE_HISTORY_SCAN_LIMIT})"),
    )


def _run_status_value(record: Any) -> str | None:
    status = getattr(record, "status", None)
    if isinstance(status, RunStatus):
        return status.value
    return str(status) if status is not None else None


async def _require_successful_source_run(thread_id: str, run_id: str, request: Request) -> RunRecord:
    run_mgr = get_run_manager(request)
    user_id = await get_current_user(request)
    record = await run_mgr.get(run_id, user_id=user_id)
    if record is None:
        # The run-event journal is the authoritative lookup above. This fallback

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Regenerate the latest turn instead of an old one that fell outside the 200-checkpoint window.
  2. Verify the message id exists in the thread's checkpointed state (GET thread state and search messages).
  3. If long threads are the norm, raise REGENERATE_HISTORY_SCAN_LIMIT in the backend and restart the Gateway.
  4. For messages that never checkpointed (aborted turns), resend the user message as a new run.
Defensive patterns

Strategy: fallback

Validate before calling

const state = await getThreadState(threadId);
const hasMsg = state.messages.some(m => m.id === humanMessageId);
if (!hasMsg) { /* id stale or beyond history; refresh */ }

Try / catch

try { await regeneratePrepare(threadId, messageId); } catch (e) { if (e.status === 409 && /recent checkpoint history/.test(e.detail)) { await refreshAndRegenerateLatest(threadId); } else throw e; }

Prevention

When it happens

Trigger: Regenerating a message older than the 200-checkpoint scan window; the human message never reached a checkpoint (interrupted before first checkpoint write); message id that exists only in the live stream, not in any checkpointed state.

Common situations: Very long threads (each graph step writes a checkpoint, so 200 covers few turns); regenerate targeting a message whose turn was aborted pre-checkpoint; stale client id.

Related errors


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