bytedance/deer-flow · error · HTTPException
The source user message is missing an id
Error message
The source user message is missing an id
What it means
Raised in _prepare_regenerate_payload (HTTP 409) when the preceding human message exists but carries no message id. The base-checkpoint lookup keys on the human message id (find_checkpoint_before_message_chronologically), so an id-less user message makes the rewind unaddressable and regenerate is refused.
Source
Thrown at backend/app/gateway/routers/thread_runs.py:682
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:
raise HTTPException(status_code=409, detail="Could not find the user message for this assistant response")
if target_run_id is None:
raise HTTPException(status_code=409, detail="Could not find source run for assistant message")
previous_human_id = _message_id(previous_human)
if not previous_human_id:
raise HTTPException(status_code=409, detail="The source user message is missing an id")
base_checkpoint_tuple = await _find_base_checkpoint_before_human(
thread_id,
previous_human_id,
request,
head_checkpoint=latest_checkpoint,
)
checkpoint = _checkpoint_response(base_checkpoint_tuple)
metadata = {
"regenerate_from_message_id": message_id,
"regenerate_from_run_id": target_run_id,
"regenerate_checkpoint_id": checkpoint["checkpoint_id"],
}
regenerate_input: dict[str, Any] = {"messages": [_clean_human_message_for_regenerate(previous_human)]}
latest_values = latest_checkpoint.values if isinstance(latest_checkpoint.values, dict) else {}
latest_title = latest_values.get("title")
if isinstance(latest_title, str) and latest_title:
# Regenerate resumes from the checkpoint before the target human turn.View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Ensure every user message added to graph state has a stable id (LangChain message id or server-stamped).
- For legacy threads without ids, continue the conversation in a new thread rather than regenerating.
- Audit custom middleware/extensions that mutate checkpointed messages and preserve the id field.
Example fix
# before state["messages"].append(HumanMessage(content=text)) # after import uuid state["messages"].append(HumanMessage(content=text, id=str(uuid.uuid4())))
Defensive patterns
Strategy: validation
Validate before calling
const idx = messages.findIndex(m => m.id === messageId);
const prevHuman = messages.slice(0, idx).findLast(m => m.type === 'human' && !m.hidden);
if (!prevHuman?.id) { disableRegenerate(); } Type guard
function humanMessageHasId(m: {type: string; id?: string} | undefined): boolean {
return !!m && m.type === 'human' && typeof m.id === 'string' && m.id.length > 0;
} Try / catch
try { await regeneratePrepare(threadId, messageId); } catch (e) { if (e.status === 409 && /missing an id/.test(e.detail)) { notify('Legacy turn cannot be regenerated; start a new message'); } else throw e; } Prevention
- Always stamp message ids on HumanMessage
- Keep middleware from stripping ids
- Migrate legacy id-less threads or avoid rewind on them
When it happens
Trigger: Checkpointed state where the HumanMessage object lacks an id (older LangGraph writes did not always stamp ids); messages injected programmatically without ids; deserialization that drops the id field.
Common situations: Threads created before an upgrade that started stamping message ids; custom code that appends HumanMessage(id=None); middleware that rewrites messages and loses ids.
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/430000a03d764e36.
Report an issue: GitHub.