{"record":{"id":"c7f9405a219cdd08","repo":"stablyai/orca","slug":"terminal-gone","errorCode":null,"errorMessage":"terminal_gone","messagePattern":"terminal_gone","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"info","filePath":"src/main/daemon/daemon-pty-router.ts","lineNumber":321,"sourceCode":"\n  getLegacyAdapters(): readonly DaemonPtyAdapter[] {\n    return this.legacy\n  }\n\n  getAllAdapters(): readonly DaemonPtyAdapter[] {\n    return this.allAdapters()\n  }\n\n  private adapterFor(sessionId: string): DaemonPtyAdapter {\n    return this.sessionAdapters.get(sessionId) ?? this.current\n  }\n\n  private adapterForInspection(sessionId: string): DaemonPtyAdapter {\n    const adapter =\n      this.sessionAdapters.get(sessionId) ??\n      this.allAdapters().find((candidate) => candidate.hasPty(sessionId))\n    if (!adapter) {\n      throw new Error('terminal_gone')\n    }\n    this.sessionAdapters.set(sessionId, adapter)\n    return adapter\n  }\n\n  private allAdapters(): DaemonPtyAdapter[] {\n    return [this.current, ...this.legacy]\n  }\n}\n","sourceCodeStart":303,"sourceCodeEnd":331,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/daemon/daemon-pty-router.ts#L303-L331","documentation":"DaemonPtyRouter.adapterForInspection is used by inspectProcess. It looks up the cached sessionAdapters entry, falls back to scanning allAdapters for one whose hasPty(sessionId) is true, and throws a plain Error('terminal_gone') when no adapter currently hosts that session. The router then caches the adapter on success so subsequent inspections are O(1).","triggerScenarios":"Calling inspectProcess for a sessionId that was never created, has already exited and been cleaned up, or whose adapter was retired (legacy adapter dropped) before inspection.","commonSituations":"Renderer asking about a stale session id after the daemon restarted; concurrent teardown racing an inspection; a session that died and was reaped from all live adapters; UI list caching an old id.","solutions":["Treat 'terminal_gone' as a terminal-not-found signal — refresh the session list and stop addressing that id.","Guard inspectProcess callers with a check against getActiveSessionIds() / listSessions() first if the cost of a throw matters.","Avoid issuing inspection concurrently with session teardown."],"exampleFix":"// before\nconst info = await router.inspectProcess(maybeStaleId)\n\n// after\nif (!router.getAllAdapters().some((a) => a.hasPty(maybeStaleId))) {\n  // session gone — refresh UI list\n} else {\n  const info = await router.inspectProcess(maybeStaleId)\n}","handlingStrategy":"validation","validationCode":"// before inspectProcess, confirm an adapter hosts the session\nconst hosted = router.getAllAdapters().some((a) => a.hasPty(sessionId))\nif (!hosted) {\n  // session gone — refresh UI list, do not call inspectProcess\n}","typeGuard":"function isTerminalGone(e: unknown): boolean {\n  return e instanceof Error && e.message === 'terminal_gone'\n}","tryCatchPattern":"try {\n  const info = await router.inspectProcess(sessionId)\n} catch (e) {\n  if (isTerminalGone(e)) {\n    // refresh session list; the id is no longer live\n  } else throw e\n}","preventionTips":["Refresh the session list from listSessions() after any terminal-exit event before re-inspecting.","Do not cache session ids across daemon reconnects without re-validating.","Avoid issuing inspectProcess concurrently with session teardown."],"tags":["daemon","pty","router","terminal-gone","session-lifecycle"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}