{"record":{"id":"4d1746dc0fd6c96d","repo":"ruvnet/ruflo","slug":"the-sibling-message-is-the-root-message-therefore","errorCode":null,"errorMessage":"The sibling message is the root message, therefore we can't add a sibling","messagePattern":"The sibling message is the root message, therefore we can't add a sibling","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ruflo/src/ruvocal/src/lib/utils/tree/addSibling.ts","lineNumber":19,"sourceCode":"import { v4 } from \"uuid\";\nimport type { Tree, TreeId, NewNode, TreeNode } from \"./tree\";\n\nexport function addSibling<T>(conv: Tree<T>, message: NewNode<T>, siblingId: TreeId): TreeId {\n\tif (conv.messages.length === 0) {\n\t\tthrow new Error(\"Cannot add a sibling to an empty conversation\");\n\t}\n\tif (!conv.rootMessageId) {\n\t\tthrow new Error(\"Cannot add a sibling to a legacy conversation\");\n\t}\n\n\tconst sibling = conv.messages.find((m) => m.id === siblingId);\n\n\tif (!sibling) {\n\t\tthrow new Error(\"The sibling message doesn't exist\");\n\t}\n\n\tif (!sibling.ancestors || sibling.ancestors?.length === 0) {\n\t\tthrow new Error(\"The sibling message is the root message, therefore we can't add a sibling\");\n\t}\n\n\tconst messageId = v4();\n\n\tconv.messages.push({\n\t\t...message,\n\t\tid: messageId,\n\t\tancestors: sibling.ancestors,\n\t\tchildren: [],\n\t} as TreeNode<T>);\n\n\tconst nearestAncestorId = sibling.ancestors[sibling.ancestors.length - 1];\n\tconst nearestAncestor = conv.messages.find((m) => m.id === nearestAncestorId);\n\n\tif (nearestAncestor) {\n\t\tif (nearestAncestor.children) {\n\t\t\tnearestAncestor.children.push(messageId);\n\t\t} else nearestAncestor.children = [messageId];","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/ruflo/src/ruvocal/src/lib/utils/tree/addSibling.ts#L1-L37","documentation":"Thrown by addSibling() when the target sibling is the root message (its ancestors array is empty or missing). The root has no parent, so a node 'next to' it would have no parent either — every tree needs exactly one root. Branching at the top level is therefore illegal; the message must be edited in place or a new conversation started.","triggerScenarios":"addSibling(conv, message, siblingId) where the found sibling has empty/undefined ancestors — i.e., siblingId === conv.rootMessageId. Typically an 'edit user message as alternative' action fired on the very first prompt of a conversation.","commonSituations":"Users editing their opening message to restart a chat; UI code that offers regeneration uniformly on every node including the root.","solutions":["Do not offer sibling insert on the root: check sibling.ancestors?.length (or id === conv.rootMessageId) and disable the action.","For 'change the first prompt' UX, create a new conversation instead of a sibling.","If editing the root content is required, mutate the root node's content rather than adding a sibling."],"exampleFix":"// before\naddSibling(conv, message, conv.rootMessageId); // throws\n\n// after\nif (siblingId === conv.rootMessageId) {\n\t// edit in place or start a new conversation\n\tconst root = conv.messages.find((m) => m.id === conv.rootMessageId)!;\n\troot.content = newContent;\n} else {\n\taddSibling(conv, message, siblingId);\n}","handlingStrategy":"validation","validationCode":"if (siblingId === conv.rootMessageId) {\n\tthrow new Error(\"cannot branch at the root message\");\n}\naddSibling(conv, message, siblingId);","typeGuard":"function isRootMessage(conv: { rootMessageId: string }, id: string): boolean {\n\treturn id === conv.rootMessageId;\n}","tryCatchPattern":null,"preventionTips":["Disable alternative/regenerate affordances on the root node in the UI.","Treat 'edit first prompt' as create-new-conversation, not sibling insert.","Assert sibling.ancestors?.length > 0 before calling addSibling."],"tags":["tree","conversation","validation","usage-error"],"backgroundTag":"invalid-tree-operation","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}