bytedance/deer-flow · warning · HTTPException
Only visible assistant messages can be regenerated
Error message
Only visible assistant messages can be regenerated
What it means
Raised in _prepare_regenerate_payload (HTTP 409) when the found target message (by id) is not a visible AI message. Regeneration only applies to assistant messages that are visible in the conversation; human messages, tool messages, or AI messages marked hidden (e.g. internal reasoning) are rejected.
Source
Thrown at backend/app/gateway/routers/thread_runs.py:658
raise HTTPException(status_code=404, detail=f"Thread {thread_id} has no checkpoint")
messages = _checkpoint_messages(latest_checkpoint)
target_index = next((i for i, message in enumerate(messages) if _message_id(message) == message_id), None)
if target_index is None:
# A response interrupted during an LLM call can be visible in the live
# stream without ever reaching a checkpoint. The server-stamped run ID
# on the latest user message is the durable link to that partial turn.
previous_human = next(
(message for message in reversed(messages) if _is_visible_human_message(message)),
None,
)
target_run_id = await _find_interrupted_target_run_id(thread_id, previous_human, request) if previous_human is not None else None
if target_run_id is None:
raise HTTPException(status_code=404, detail=f"Message {message_id} not found")
else:
target_message = messages[target_index]
if not _is_visible_ai_message(target_message):
raise HTTPException(status_code=409, detail="Only visible assistant messages can be regenerated")
latest_visible_ai = next((message for message in reversed(messages) if _is_visible_ai_message(message)), None)
if _message_id(latest_visible_ai) != message_id:
raise HTTPException(status_code=409, detail="Only the latest assistant message can be regenerated")
previous_human = next((message for message in reversed(messages[:target_index]) if _is_visible_human_message(message)), None)
target_run_id = (
await _find_target_run_id(
thread_id,
message_id,
target_message,
previous_human,
request,
)
if previous_human is not None
else None
)
if previous_human is None:View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Only expose regenerate on visible assistant text bubbles in the UI.
- Filter the messages array by type === 'ai' and not hidden before computing the target.
- Verify the id being sent corresponds to the assistant reply, not the human turn (which uses the edit flow instead).
Example fix
// before regeneratePrepare(threadId, clickedMessageId); // after const target = messages.find(m => m.id === clickedMessageId); if (target?.type !== 'ai' || target.hidden) return; regeneratePrepare(threadId, clickedMessageId);
Defensive patterns
Strategy: type-guard
Validate before calling
const target = messages.find(m => m.id === messageId);
if (!target || target.type !== 'ai' || target.hidden) { return; } Type guard
function isRegenerableMessage(m: {type: string; hidden?: boolean} | undefined): boolean {
return !!m && m.type === 'ai' && !m.hidden;
} Try / catch
try { await regeneratePrepare(threadId, messageId); } catch (e) { if (e.status === 409 && /visible assistant/.test(e.detail)) { fixMessageTargeting(); } else throw e; } Prevention
- Attach regenerate only to visible assistant bubbles
- Filter hidden/tool messages out of rewind targets
When it happens
Trigger: Passing the id of a user message or tool-call message to the regenerate endpoint; targeting an assistant message with hide_from_ui set.
Common situations: Frontend passes the wrong message from the transcript (e.g. a tool result card); internal/system AI messages leaking into UI and being targeted.
Related errors
- Checkpoint is missing checkpoint_id
- Only the latest completed user turn can be edited
- Only completed assistant text turns can be edited
- Could not find source run for assistant message
- Could not safely resolve the checkpoint before the target us
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/d4eb67b3ba39d4a5.
Report an issue: GitHub.