{"record":{"id":"7ff710fd79103124","repo":"stablyai/orca","slug":"session-opts-sessionid-is-terminating","errorCode":null,"errorMessage":"Session \"${opts.sessionId}\" is terminating","messagePattern":"Session \"(.+?)\" is terminating","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/daemon/terminal-host-session-create.ts","lineNumber":60,"sourceCode":"  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) {\n    // Why: replacing a SIGKILLed-but-unreaped child could hide two live\n    // generations behind the same public session id.\n    throw new Error(`Session \"${opts.sessionId}\" is terminating`)\n  }\n  if (opts.attachOnly) {\n    // Why: an adopted claim proves only one owner generation; it must never\n    // turn an exit race into permission to spawn an unclaimed shell.\n    throw new SessionNotFoundError(opts.sessionId)\n  }\n\n  if (existing) {\n    existing.dispose()\n    deps.sessions.delete(opts.sessionId)\n    deps.onDeadSessionRemoved(opts.sessionId)\n  }\n\n  deps.killedTombstones.clearForCreate(opts.sessionId)\n  const size = normalizePtySize(opts.cols, opts.rows)\n  const wslDistro = resolveWslSessionContext(opts)?.distro\n  const subprocess = deps.spawnSubprocess({\n    sessionId: opts.sessionId,","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/daemon/terminal-host-session-create.ts#L42-L78","documentation":"A distinct, more specific error than SessionNotFoundError: the session exists, is alive, and is marked isTerminating (e.g., it was SIGKILLed but the child has not yet been reaped). Recreating it now could hide two live generations behind the same public session id. Throwing a unique message lets callers distinguish 'in a terminal exit race' from 'genuinely gone'.","triggerScenarios":"createOrAttachTerminalSession where existing?.isAlive && existing.isTerminating, reached after the live-attach branch and not via the sessionTeardown map. The process was killed but reaping/descendant-capture is incomplete.","commonSituations":"Recreating a session immediately after sending SIGKILL but before the exit handler reaped the process; a createOrAttach racing the reap window of a killed shell; rapid kill+reopen sequences.","solutions":["Wait for the session's exit to be fully reaped (the exit handler runs) before recreating under the same id.","If you must proceed immediately, create under a new sessionId rather than reusing the terminating one.","Track isTerminating state client-side and avoid reusing ids that are mid-exit.","Ensure the kill->reap->recreate sequence is serialized, not concurrent."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"function isSessionTerminating(e: unknown, sessionId: string): boolean {\n  return e instanceof Error && e.message === `Session \"${sessionId}\" is terminating`\n}","tryCatchPattern":"try {\n  return await createOrAttachTerminalSession(opts, deps)\n} catch (e) {\n  if (e instanceof Error && e.message === `Session \"${opts.sessionId}\" is terminating`) {\n    await waitForSessionReaped(opts.sessionId)  // exit handler runs\n    return await createOrAttachTerminalSession(opts, deps)\n  }\n  throw e\n}","preventionTips":["Wait for the killed session to be fully reaped before recreating under the same id.","If immediate creation is required, use a new sessionId instead of reusing the terminating one.","Serialize the kill->reap->recreate sequence; do not overlap SIGKILL with a fresh create."],"tags":["session","terminating","race","lifecycle"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}