{"record":{"id":"fcdc58181dcea79b","repo":"earendil-works/pi","slug":"not-found-fcdc58","errorCode":"not_found","errorMessage":"Session not found: ${id}","messagePattern":"Session not found: (.+?)","errorType":"exception","errorClass":"SessionError","httpStatus":null,"severity":"error","filePath":"packages/agent/src/harness/session/memory.ts","lineNumber":189,"sourceCode":"\tasync delete(metadata: SessionMetadata): Promise<void> {\n\t\tthis.sessions.delete(metadata.id);\n\t}\n\n\tasync fork(source: SessionMetadata, options: ForkOptions & SessionCreateOptions = {}): Promise<Session> {\n\t\tconst sourceStorage = this.requireStorage(source.id);\n\t\tconst id = options.id ?? uuidv7();\n\t\tif (this.sessions.has(id)) throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n\t\tconst storage = sourceStorage.fork(\n\t\t\t{ id, createdAt: Date.now(), parentSessionId: options.parentSessionId ?? source.id },\n\t\t\toptions,\n\t\t);\n\t\tthis.sessions.set(id, storage);\n\t\treturn new Session(storage);\n\t}\n\n\tprivate requireStorage(id: string): InMemorySessionStorage {\n\t\tconst storage = this.sessions.get(id);\n\t\tif (!storage) throw new SessionError(\"not_found\", `Session not found: ${id}`);\n\t\treturn storage;\n\t}\n}\n","sourceCodeStart":171,"sourceCodeEnd":193,"githubUrl":"https://github.com/earendil-works/pi/blob/4af9d21d3b4d664e4a29fcabfec85171077248e3/packages/agent/src/harness/session/memory.ts#L171-L193","documentation":"Thrown by InMemorySessionRepo.requireStorage when repo.open(metadata) or repo.fork(source) references a session id this repo instance has no storage for. The repo keeps sessions in a plain in-memory Map that is populated only by create(), removed by delete(), and wiped when the process exits, so the id must have been created in the same process and repo instance. It signals a lifecycle mismatch (never created, deleted, or wrong repo), not data corruption.","triggerScenarios":"Calling repo.open({ id }) with an id that was never passed to repo.create({ id }); calling open() after repo.delete() removed the session; calling repo.fork(source) where source.id belongs to a different InMemorySessionRepo instance; replaying metadata loaded from disk into a freshly started process.","commonSituations":"Persisting session metadata while running InMemorySessionRepo, then restarting the process (memory is wiped while the metadata survives); running one repo instance per test or per worker and opening a session created by another; deleting a session in one code path while another still opens it; typos in ids copied from logs.","solutions":["Verify the id exists first: const known = (await repo.list()).some((m) => m.id === id), and create it when missing","Create sessions before opening them: repo.create({ id }) already returns the Session, so open() is only needed for metadata known to this repo","Use a single repo instance per process and pass it around instead of constructing new ones","Switch to a durable SessionRepo/SessionStorage implementation when sessions must survive restarts"],"exampleFix":"// before\nconst session = await repo.open({ id: savedId, createdAt: Date.now() });\n// after\nconst meta = (await repo.list()).find((m) => m.id === savedId);\nconst session = meta ? await repo.open(meta) : await repo.create({ id: savedId });","handlingStrategy":"validation","validationCode":"const sessionExists = async (repo: SessionRepo, id: string): Promise<boolean> =>\n  (await repo.list()).some((m) => m.id === id);\n\nif (!(await sessionExists(repo, savedId))) {\n  await repo.create({ id: savedId });\n}","typeGuard":null,"tryCatchPattern":"try {\n  session = await repo.open(meta);\n} catch (error) {\n  if (error instanceof SessionError && error.code === 'not_found') {\n    session = await repo.create({ id: meta.id }); // or surface 'unknown session' to the caller\n  } else {\n    throw error;\n  }\n}","preventionTips":["Keep one repo instance per process and share it instead of constructing new ones","Treat InMemorySessionRepo ids as ephemeral; pair them with durable storage before persisting anywhere","Never open a session after delete() removed it","Prefer the Session object returned by create()/fork() over reopening by id"],"tags":["session","in-memory","not-found","lifecycle"],"backgroundTag":"session-not-found","analyzedSha":"4af9d21d3b4d664e4a29fcabfec85171077248e3","analyzedAt":"2026-08-24T13:07:14.692Z","schemaVersion":2},"datasetVersion":"2026-08-24T17:17:21.512Z"}