{"record":{"id":"ed83e3e89126111b","repo":"can1357/oh-my-pi","slug":"entry-leafid-not-found","errorCode":null,"errorMessage":"Entry ${leafId} not found","messagePattern":"Entry (.+?) not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/session/session-manager.ts","lineNumber":2679,"sourceCode":"\t\t\tparentId: branchFromId,\n\t\t\ttimestamp: nowIso(),\n\t\t\tfromId: branchFromId ?? \"root\",\n\t\t\tsummary,\n\t\t\tdetails,\n\t\t\tfromExtension,\n\t\t};\n\t\tthis.#recordEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/**\n\t * Create a new session file containing only the path from root to `leafId`.\n\t * Returns the new file path, or undefined when not persisting.\n\t */\n\tcreateBranchedSession(leafId: string): string | undefined {\n\t\tconst sourceSessionFile = this.#sessionFile;\n\t\tconst branchPath = this.getBranch(leafId);\n\t\tif (branchPath.length === 0) throw new Error(`Entry ${leafId} not found`);\n\n\t\t// Drop label entries from the path; recreate them fresh from the resolved map.\n\t\tconst entriesToKeep = branchPath.filter(entry => entry.type !== \"label\");\n\t\tconst keptIds = new Set(entriesToKeep.map(entry => entry.id));\n\t\tconst labelsToCarry: Array<{ targetId: string; label: string }> = [];\n\t\tfor (const [targetId, label] of this.#index.labelsInEffect()) {\n\t\t\tif (keptIds.has(targetId)) labelsToCarry.push({ targetId, label });\n\t\t}\n\n\t\tconst timestamp = nowIso();\n\t\tconst newSessionId = mintSessionId();\n\t\tthis.#reconcileSessionDirForFallback();\n\t\tconst newSessionFile = path.join(this.#sessionDir, `${fileSafeTimestamp(timestamp)}_${newSessionId}.jsonl`);\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: newSessionId,\n\t\t\ttimestamp,","sourceCodeStart":2661,"sourceCodeEnd":2697,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-manager.ts#L2661-L2697","documentation":"SessionManager.createBranchedSession(leafId) extracts the root-to-leaf path into a new session file. It derives the path via getBranch(leafId); when that returns an empty array — which happens when leafId does not resolve to any entry in the session tree — it throws this Error instead of silently producing an empty session.","triggerScenarios":"Calling createBranchedSession with an id absent from the session index, an id from another session file, or after the targeted entry was removed by earlier branch/prune operations so getBranch can no longer reconstruct a path.","commonSituations":"Persisting a forked conversation after the UI held a stale leaf id across a session reload; exporting a subtree using an id captured before the tree was modified; consumers confusing message ids with entry ids.","solutions":["Fetch the current leaf id from the session (e.g. the last entry of the active branch) and pass that instead of a cached id.","Confirm the id is an entry id of this same session file; re-read the entries and search for it.","If the intended leaf was pruned, undo the pruning or pick a surviving ancestor entry on the same path.","Wrap in try-catch and surface 'session entry not found' to the user, offering to fork from the current tip."],"exampleFix":"// before\nsession.createBranchedSession(cachedLeafId);\n// after\nconst entries = session.getBranch(session.currentLeafId ?? undefined);\nconst target = entries.find(e => e.id === leafId);\nconst newFile = target ? session.createBranchedSession(target.id) : session.createBranchedSession(session.currentLeafId);","handlingStrategy":"validation","validationCode":"const leafExists = session.getEntries().some(e => e.id === leafId);\nif (!leafExists) throw new Error(`createBranchedSession: ${leafId} not in session`);\nconst newPath = session.createBranchedSession(leafId);","typeGuard":null,"tryCatchPattern":"try {\n  return session.createBranchedSession(leafId);\n} catch (err) {\n  if (err.message.includes(\"not found\")) {\n    logger.warn(`Leaf ${leafId} gone; forking from current tip`);\n    return session.createBranchedSession(session.currentLeafId);\n  }\n  throw err;\n}","preventionTips":["Resolve leaf ids immediately before forking; do not cache across reloads.","Only pass ids that came from this session instance's entries.","After prune/branch operations, re-resolve the leaf instead of reusing the old one.","Distinguish message ids from session entry ids in your own data model."],"tags":["session","argument-validation","branching"],"backgroundTag":"invalid-entry-id","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}