{"record":{"id":"a3e62d1ce1305f9d","repo":"ruvnet/ruflo","slug":"message-not-found","errorCode":null,"errorMessage":"Message not found","messagePattern":"Message not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ruflo/src/ruvocal/src/lib/utils/tree/buildSubtree.ts","lineNumber":8,"sourceCode":"import type { Tree, TreeId, TreeNode } from \"./tree\";\n\nexport function buildSubtree<T>(conv: Tree<T>, id: TreeId): TreeNode<T>[] {\n\tif (!conv.rootMessageId) {\n\t\tif (conv.messages.length === 0) return [];\n\t\t// legacy conversation slice up to id\n\t\tconst index = conv.messages.findIndex((m) => m.id === id);\n\t\tif (index === -1) throw new Error(\"Message not found\");\n\t\treturn conv.messages.slice(0, index + 1);\n\t} else {\n\t\t// find the message with the right id then create the ancestor tree\n\t\tconst message = conv.messages.find((m) => m.id === id);\n\t\tif (!message) throw new Error(\"Message not found\");\n\n\t\treturn [\n\t\t\t...(message.ancestors?.map((ancestorId) => {\n\t\t\t\tconst ancestor = conv.messages.find((m) => m.id === ancestorId);\n\t\t\t\tif (!ancestor) throw new Error(\"Ancestor not found\");\n\t\t\t\treturn ancestor;\n\t\t\t}) ?? []),\n\t\t\tmessage,\n\t\t];\n\t}\n}\n","sourceCodeStart":1,"sourceCodeEnd":25,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/ruflo/src/ruvocal/src/lib/utils/tree/buildSubtree.ts#L1-L25","documentation":"Thrown by buildSubtree() when asked to materialize the message chain up to a given id but no message with that id exists in the conversation. For tree conversations the target lookup and each ancestor lookup can both fail ('Message not found' vs 'Ancestor not found'); for legacy conversations the id must appear in the flat message array.","triggerScenarios":"buildSubtree(conv, id) with an id that is absent from conv.messages: deleted message, id from another conversation, or a client holding a stale tree snapshot after concurrent edits.","commonSituations":"Rendering a permalink/share link whose target message was deleted afterwards; navigating to ?message=<id> after the conversation was trimmed; concurrent sessions where one deletes messages while another builds subtrees.","solutions":["Validate the id against the current conversation before building: conv.messages.some((m) => m.id === id).","For share/permalink pages, fall back to the whole conversation or a 404 when the target was deleted.","Refresh the conversation from the server before operating on user-supplied ids.","Fix data integrity if ancestors reference missing nodes — the sibling 'Ancestor not found' error indicates dangling ancestor ids."],"exampleFix":"// before\nconst nodes = buildSubtree(conv, messageId);\n\n// after\nif (!conv.messages.some((m) => m.id === messageId)) {\n\tthrow new Error(\"message no longer exists\");\n}\nconst nodes = buildSubtree(conv, messageId);","handlingStrategy":"validation","validationCode":"if (!conv.messages.some((m) => m.id === messageId)) {\n\tthrow new Error(`message ${messageId} not found in conversation`);\n}\nconst subtree = buildSubtree(conv, messageId);","typeGuard":"function hasMessage(conv: { messages: { id: string }[] }, id: string): boolean {\n\treturn conv.messages.some((m) => m.id === id);\n}","tryCatchPattern":"try {\n\tconst nodes = buildSubtree(conv, messageId);\n} catch (err) {\n\tif (String(err) === \"Message not found\" || String(err) === \"Ancestor not found\") {\n\t\treturn new Response(\"Message no longer exists\", { status: 404 });\n\t}\n\tthrow err;\n}","preventionTips":["Validate deep-link/permalink message ids against the live conversation before rendering.","Return 404 (not 500) for deleted share-target messages.","Repair dangling ancestor references during data migrations to avoid the sibling 'Ancestor not found' failure."],"tags":["tree","conversation","stale-state","validation"],"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"}