{"record":{"id":"09e72a84503e6c70","repo":"can1357/oh-my-pi","slug":"entry-targetid-not-found","errorCode":null,"errorMessage":"Entry ${targetId} not found","messagePattern":"Entry (.+?) not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/session/session-manager.ts","lineNumber":2552,"sourceCode":"\n\tgetEntry(id: string): SessionEntry | undefined {\n\t\treturn this.#index.get(id);\n\t}\n\n\t/** All direct children of an entry. */\n\tgetChildren(parentId: string): SessionEntry[] {\n\t\treturn this.#index.childrenOf(parentId);\n\t}\n\n\tgetLabel(id: string): string | undefined {\n\t\treturn this.#index.labelFor(id);\n\t}\n\n\t/**\n\t * Set or clear a label on an entry. Pass undefined/empty to clear.\n\t */\n\tappendLabelChange(targetId: string, label: string | undefined): string {\n\t\tif (!this.#index.has(targetId)) throw new Error(`Entry ${targetId} not found`);\n\n\t\tconst entry: LabelEntry = { type: \"label\", ...this.#freshEntryFields(), targetId, label };\n\t\tthis.#recordEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/**\n\t * Walk from an entry to root, returning entries in path order. Includes all\n\t * entry types; use buildSessionContext() for the resolved LLM messages.\n\t */\n\tgetBranch(fromId?: string): SessionEntry[] {\n\t\treturn this.#index.pathTo(fromId ?? this.#index.leafId());\n\t}\n\n\t/**\n\t * Build the session context (LLM messages), or — with `{ transcript: true }` —\n\t * the full-history display transcript, from the current leaf path.\n\t */","sourceCodeStart":2534,"sourceCodeEnd":2570,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-manager.ts#L2534-L2570","documentation":"appendLabelChange writes a label entry that targets an existing entry by id (targetId). If the target id is absent from the session index, the label would reference a nonexistent entry, so the call throws before recording anything. Only labels on live entries in the currently loaded session are allowed.","triggerScenarios":"Calling appendLabelChange(targetId, label) with an id not present in the current session's entry index — id from another session, pruned by compaction, fabricated, or from a stale in-memory list after reloading the session file.","commonSituations":"Labelling entries after the session was compacted (old ids gone); mixing ids across branched sessions; UI holding stale selection while the session reloaded underneath it.","solutions":["Refresh the entry list from the current SessionManager and use a currently valid entry id.","Check the target still exists before labelling (lookup/getEntry first).","Reload or switch to the session that actually contains the target entry.","Skip labels for entries missing from the index (they were compacted away)."],"exampleFix":"// before\nmgr.appendLabelChange(oldId, \"done\"); // may throw\n// after\nconst target = mgr.getEntry(oldId);\nif (target) mgr.appendLabelChange(oldId, \"done\");","handlingStrategy":"validation","validationCode":"if (!mgr.hasEntry(targetId)) {\n  return; // entry was compacted away or belongs to another session\n}","typeGuard":"function entryExists(mgr, id) {\n  return mgr.getEntry(id) != null;\n}","tryCatchPattern":"try {\n  mgr.appendLabelChange(targetId, label);\n} catch (err) {\n  if (/Entry .* not found/.test(err.message)) {\n    logger.warn(\"Label target missing; skipping\", { targetId });\n  } else throw err;\n}","preventionTips":["Refresh your entry list from the manager before labelling.","Skip labels for entries absent after compaction.","Never mix entry ids between sessions or manager instances."],"tags":["session","labels","invalid-argument"],"backgroundTag":"entry-not-found","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}