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

  1. Only expose regenerate on visible assistant text bubbles in the UI.
  2. Filter the messages array by type === 'ai' and not hidden before computing the target.
  3. 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

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


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