{"record":{"id":"cce5bc583b16c618","repo":"can1357/oh-my-pi","slug":"entry-branchfromid-not-found","errorCode":null,"errorMessage":"Entry ${branchFromId} not found","messagePattern":"Entry (.+?) not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/session/session-manager.ts","lineNumber":2613,"sourceCode":"\t/** All session entries (excludes header). Returns a shallow copy. */\n\tgetEntries(): SessionEntry[] {\n\t\treturn [...this.#entries];\n\t}\n\n\t/**\n\t * The session as a tree. A well-formed session has exactly one root; orphaned\n\t * entries (broken parent chain) are returned as roots too.\n\t */\n\tgetTree(): SessionTreeNode[] {\n\t\treturn this.#index.tree(this.#entries);\n\t}\n\n\t/**\n\t * Move the leaf to an earlier entry so the next append forms a new branch.\n\t * Existing entries are never modified or deleted.\n\t */\n\tbranch(branchFromId: string): void {\n\t\tif (!this.#index.has(branchFromId)) throw new Error(`Entry ${branchFromId} not found`);\n\t\tthis.#setLeaf(branchFromId);\n\t}\n\n\t/** Reset the leaf to null so the next append creates a new root entry. */\n\tresetLeaf(): void {\n\t\tthis.#setLeaf(null);\n\t}\n\n\t/**\n\t * Durably move the active branch past a discarded entry.\n\t *\n\t * The loader reconstructs the active branch from the last physical journal\n\t * entry, so changing the in-memory leaf alone is lost on reload. Known\n\t * metadata children are chained onto the discarded entry's parent before the\n\t * entry is removed. If any child may carry content, the subtree is preserved\n\t * off-branch instead. Both paths append a metadata-only branch marker and\n\t * rewrite the journal, making the selected path durable.\n\t */","sourceCodeStart":2595,"sourceCodeEnd":2631,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-manager.ts#L2595-L2631","documentation":"branch() moves the session leaf to an earlier entry so subsequent appends form a new branch of the entry tree. It throws if branchFromId does not exist in the session index, since there is no entry to move the leaf to. Existing entries are never modified or deleted; the id must point at a live entry in the currently loaded session.","triggerScenarios":"Calling SessionManager.branch(branchFromId) with an id not in the current session — id from a different session/file, an entry removed by compaction, or a stale id after the session was reloaded or reset.","commonSituations":"Building a 'fork from earlier message' UI that cached entry ids across a session reload; forking from another session's transcript; branching from an id destroyed by compaction.","solutions":["Fetch valid entry ids from the current SessionManager (entry list / traversal) instead of cached ids.","Use resetLeaf() if you actually want to branch from a fresh root rather than an existing entry.","Verify the target entry exists in the index before calling branch.","Load the session containing the target entry before branching."],"exampleFix":"// before\nmgr.branch(cachedId); // Entry <id> not found\n// after\nconst entries = mgr.getEntries();\nconst target = entries.find(e => e.id === cachedId);\nif (target) mgr.branch(target.id); else mgr.resetLeaf();","handlingStrategy":"validation","validationCode":"if (!mgr.hasEntry(branchFromId)) {\n  mgr.resetLeaf(); // branch from a fresh root instead\n  return;\n}","typeGuard":"function canBranch(mgr, id) {\n  return mgr.getEntry(id) != null;\n}","tryCatchPattern":"try {\n  mgr.branch(id);\n} catch (err) {\n  if (/Entry .* not found/.test(err.message)) {\n    mgr.resetLeaf(); // fall back to a new root branch\n  } else throw err;\n}","preventionTips":["Re-fetch entry ids from the live session before forking.","Use resetLeaf() when you want a brand-new root instead of a specific entry.","Reload the containing session before branching on ids read from a session file."],"tags":["session","branching","invalid-argument"],"backgroundTag":"entry-not-found","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}