datawhalechina/hello-agents · error · ValueError
消息 {at_message_id} 不存在
Error message
消息 {at_message_id} 不存在 What it means
Conversation.fork raises ValueError when at_message_id does not match any message_id in the conversation's message list. Forking needs an anchor message to copy history up to (inclusive) and mark as the branch point, so an unknown anchor is unrecoverable.
Source
Thrown at Co-creation-projects/lcyting-StockSage-agent/HelloAgents Optimized/hello_agents/core/conversation.py:56
return self.messages[start:end]
def get_last_message(self) -> Optional[Message]:
return self.messages[-1] if self.messages else None
def get_message_by_id(self, message_id: str) -> Optional[Message]:
for m in self.messages:
if m.message_id == message_id:
return m
return None
def fork(self, at_message_id: str, new_name: str = "") -> "Conversation":
target_idx = -1
for i, m in enumerate(self.messages):
if m.message_id == at_message_id:
target_idx = i
break
if target_idx == -1:
raise ValueError(f"消息 {at_message_id} 不存在")
new_conv = Conversation(
name=new_name or f"{self.name} (分支)",
system_prompt=self.system_prompt,
metadata={**self.metadata, "forked_from": self.conversation_id},
)
for i, m in enumerate(self.messages[: target_idx + 1]):
if i == target_idx:
fork_msg = m.model_copy(deep=True)
fork_msg.branch_point = True
fork_msg.conversation_id = new_conv.conversation_id
fork_msg.parent_id = (
new_conv.messages[-1].message_id if new_conv.messages else None
)
new_conv.messages.append(fork_msg)
else:
copied = m.model_copy(deep=True)View on GitHub (pinned to 606a07d341)
Solutions
- Use a message_id taken directly from conversation.messages of the same conversation object.
- Refresh the conversation state in the UI before offering a fork action.
- If the anchor was deleted, fork from the current last message (messages[-1].message_id) instead.
Example fix
# before
new_conv = conv.fork(at_message_id=user_picked_id) # ValueError if stale
# after
ids = [m.message_id for m in conv.messages]
if user_picked_id not in ids:
user_picked_id = ids[-1]
new_conv = conv.fork(at_message_id=user_picked_id) Defensive patterns
Strategy: type-guard
Validate before calling
message_ids = {m.message_id for m in conv.messages}
if at_message_id not in message_ids:
at_message_id = conv.messages[-1].message_id # fork from latest
new_conv = conv.fork(at_message_id=at_message_id) Type guard
def is_fork_anchor(conv: "Conversation", message_id: str) -> bool:
return any(m.message_id == message_id for m in conv.messages) Try / catch
try:
new_conv = conv.fork(at_message_id=anchor_id)
except ValueError as e:
if "不存在" in str(e):
anchor_id = conv.messages[-1].message_id
new_conv = conv.fork(at_message_id=anchor_id)
else:
raise Prevention
- Always source the anchor id from the same conversation object being forked.
- Refresh conversation state in the UI before exposing fork actions.
- Fall back to forking at the latest message when the anchor is gone.
When it happens
Trigger: Calling fork(at_message_id=...) with an id from another conversation, a deleted message, or a malformed/truncated id string.
Common situations: UI passing a message id from a stale conversation snapshot; concurrent deletion of messages between render and fork; ids persisted before a schema change.
Related errors
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/f7ed9d325c7f87dc.
Report an issue: GitHub.