{"record":{"id":"ff2f13e67c37b3f1","repo":"stablyai/orca","slug":"session-not-found-sessionid-ff2f13","errorCode":null,"errorMessage":"Session not found: ${sessionId}","messagePattern":"Session not found: (.+?)","errorType":"exception","errorClass":"SessionNotFoundError","httpStatus":null,"severity":"error","filePath":"src/main/daemon/terminal-host-session-create.ts","lineNumber":39,"sourceCode":"  onDeadSessionRemoved: (sessionId: string) => void\n  onSessionCreated: (sessionId: string, generation: string | undefined, isAlive: boolean) => void\n  onSessionExit: (sessionId: string, generation: string | undefined) => void\n}\n\nexport async function createOrAttachTerminalSession(\n  opts: InternalCreateOrAttachOptions,\n  deps: TerminalHostSessionCreateDependencies\n): Promise<CreateOrAttachResult> {\n  if (deps.creationFenced) {\n    throw new Error('Terminal host is shutting down')\n  }\n  opts.onSessionResolved?.(opts.sessionId)\n  const existing = deps.sessions.get(opts.sessionId)\n\n  // Why: descendant capture must finish before attach or recreation, or the\n  // caller could receive a doomed session while teardown owns its process.\n  if (deps.sessionTeardown.get(opts.sessionId) || existing?.isTerminating) {\n    throw new SessionNotFoundError(opts.sessionId)\n  }\n\n  if (existing && existing.isAlive && !existing.isTerminating) {\n    const snapshot = existing.getSnapshot()\n    existing.detachAllClients()\n    const token = existing.attachClient(opts.streamClient)\n    return {\n      isNew: false,\n      snapshot,\n      pid: existing.pid,\n      shellState: existing.shellState,\n      incarnationId: existing.incarnationId,\n      ...getDaemonSessionResultMetadata(existing),\n      attachToken: token\n    }\n  }\n\n  if (existing?.isAlive && existing.isTerminating) {","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/daemon/terminal-host-session-create.ts#L21-L57","documentation":"SessionNotFoundError from createOrAttachTerminalSession: the session id is in active teardown (sessionTeardown holds it) or the existing session is marked isTerminating. Descendant capture must finish before attach or recreation, so a session being torn down is reported as not found rather than handed out — handing it out could deliver a doomed session to the caller while teardown owns its process.","triggerScenarios":"createOrAttachTerminalSession where deps.sessionTeardown.get(opts.sessionId) is truthy or existing?.isTerminating is true, hit before the live-attach or terminate-specific branches.","commonSituations":"A createOrAttach for a sessionId that is concurrently being killed/teardown; an attach racing session exit; recreating a session whose teardown has not finished capturing descendants.","solutions":["Wait for the session's teardown to complete (descendant capture) before retrying createOrAttach.","If attaching, retry after the terminating session is fully reaped.","Avoid issuing createOrAttach for ids known to be in teardown; track teardown state client-side.","If recreation is intended, ensure prior teardown finishes first so a new generation can spawn cleanly."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Check teardown state before createOrAttach to avoid the not-found round-trip\nif (deps.sessionTeardown.get(sessionId) || existing?.isTerminating) {\n  await waitForTeardown(sessionId)\n}","typeGuard":"import { SessionNotFoundError } from './types'\nfunction isSessionNotFoundDuringTeardown(e: unknown): boolean {\n  return e instanceof SessionNotFoundError\n}","tryCatchPattern":"try {\n  return await createOrAttachTerminalSession(opts, deps)\n} catch (e) {\n  if (e instanceof SessionNotFoundError && isSessionInTeardown(sessionId)) {\n    await waitForTeardownComplete(sessionId)\n    return await createOrAttachTerminalSession(opts, deps)\n  }\n  throw e\n}","preventionTips":["Wait for a session's teardown (descendant capture) to finish before reusing its id.","Track teardown state client-side to avoid issuing createOrAttach for ids being torn down.","Serialize kill->teardown->recreate rather than overlapping them."],"tags":["session","teardown","not-found","lifecycle"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}