{"record":{"id":"2365455242df9de9","repo":"ruvnet/ruflo","slug":"cannot-add-a-sibling-to-an-empty-conversation","errorCode":null,"errorMessage":"Cannot add a sibling to an empty conversation","messagePattern":"Cannot add a sibling to an empty conversation","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ruflo/src/ruvocal/src/lib/utils/tree/addSibling.ts","lineNumber":6,"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({","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/ruflo/src/ruvocal/src/lib/utils/tree/addSibling.ts#L1-L24","documentation":"Thrown by addSibling() in the tree utilities when the conversation has zero messages. Sibling insertion is defined as adding a node next to an existing one under the same parent; with an empty messages array there is no reference node and no parent, so the operation is meaningless — the first message must be created with addChildren instead.","triggerScenarios":"Calling addSibling(conv, message, siblingId) on a fresh/empty conversation (conv.messages.length === 0), typically during initialization code that unconditionally inserts alternatives.","commonSituations":"Regenerating a response on a brand-new conversation before the prompt was stored; UI wiring the 'edit as new branch' button on an empty thread; tests seeding conversations starting from a sibling insert.","solutions":["Create the first message with addChildren(conv, message) — no siblingId needed.","Guard the regenerate/sibling code path: if conv.messages.length === 0, route to addChildren.","Ensure the user's prompt is persisted before enabling sibling-type actions in the UI."],"exampleFix":"// before\naddSibling(conv, message, someId); // throws on empty conv\n\n// after\nif (conv.messages.length === 0) {\n\taddChildren(conv, message);\n} else {\n\taddSibling(conv, message, someId);\n}","handlingStrategy":"validation","validationCode":"if (conv.messages.length === 0) {\n\taddChildren(conv, message); // first message becomes the root\n} else {\n\taddSibling(conv, message, siblingId);\n}","typeGuard":"function hasMessages<T>(conv: { messages: T[] }): conv is { messages: [T, ...T[]] } {\n\treturn conv.messages.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Gate sibling/branch actions on conversation non-emptiness in the UI.","Persist the user's first message before enabling alternative-generation controls.","Unit-test tree helpers with empty and single-node fixtures."],"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"}