{"record":{"id":"98bb879b3c05f2be","repo":"stablyai/orca","slug":"terminal-pane-owner-unverified","errorCode":null,"errorMessage":"terminal_pane_owner_unverified","messagePattern":"terminal_pane_owner_unverified","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/pty.ts","lineNumber":855,"sourceCode":"    result = await provider.spawn({\n      ...spawnOptions,\n      sessionId: owner.ptyId,\n      attachOnly: true,\n      expectedIncarnationId: owner.runtimeIncarnationId ?? owner.persistedIncarnationId,\n      expectedIncarnationIsAuthoritative: owner.runtimeIncarnationId !== undefined,\n      isNewSession: undefined,\n      command: undefined,\n      commandDelivery: undefined,\n      startupCommandDelivery: undefined,\n      launchAgent: undefined,\n      startupIngress: undefined,\n      agentSessionEnsure: undefined,\n      agentSessionCreateOperationId: undefined,\n      onPtySpawnCommitted: undefined\n    })\n  } catch (error) {\n    if (error instanceof TerminalSessionOwnerUnverifiedError) {\n      throw new Error('terminal_pane_owner_unverified')\n    }\n    // Why: translate before paired-runtime RPC strips the socket error's code and syscall.\n    if (isDaemonEndpointGoneError(error)) {\n      throw new TerminalHostGoneError()\n    }\n    if (!isPtyAlreadyGoneError(error)) {\n      throw error\n    }\n    const ownerBeforeRetire = args.resolveOwner?.()\n    if (\n      ownerBeforeRetire &&\n      (ownerBeforeRetire.ptyId !== owner.ptyId ||\n        ownerBeforeRetire.runtimeIncarnationId !== owner.runtimeIncarnationId ||\n        ownerBeforeRetire.hasPersistedBinding !== owner.hasPersistedBinding ||\n        ownerBeforeRetire.persistedIncarnationId !== owner.persistedIncarnationId)\n    ) {\n      throw new Error('terminal_pane_owner_changed')\n    }","sourceCodeStart":837,"sourceCodeEnd":873,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/pty.ts#L837-L873","documentation":"Thrown at pty.ts:854-855 when provider.spawn() during attachStablePaneOwner rejects with TerminalSessionOwnerUnverifiedError. That error (daemon-errors.ts:24) is raised by the daemon's session router (daemon-session-owner-resolution.ts:99,116) when a session's owner cannot be verified: the resolution kind is 'unknown' (session id not recognized across providers), or a SessionNotFoundError occurred with multiple providers and the router cannot prove which provider owns the session. It signals 'cannot prove this pane belongs to the claimed owner' — a safety refusal, not a crash.","triggerScenarios":"Reattaching to a stable terminal pane (attachOnly spawn) whose sessionId/incarnation the daemon cannot resolve to a known owner: the session was never created on this daemon, the incarnation id changed (daemon restarted and lost the session), or multiple providers are configured and ownership is ambiguous after a SessionNotFoundError.","commonSituations":"Daemon restarted (lost in-memory session registry) while the renderer still holds a stable-pane binding; a race between a pane retiring and a reattach attempt; remote/SSH daemon where the session id was never published to this daemon; incarnation mismatch after a host handover.","solutions":["Treat this as 'pane cannot be reattached' — create a fresh terminal session instead of retrying the attach.","If the daemon was expected to know the session, confirm the daemon is the same instance (check daemon endpoint ownership / incarnation) — a restarted daemon legitimately does not recognize old sessions.","Verify the ptyId/incarnationId passed to spawn match a session the daemon created.","Do not loop/retry the attach: the comment at pty.ts:857 notes the daemon endpoint may be gone, which is a separate TerminalHostGoneError path."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"function isTerminalPaneOwnerUnverified(e: unknown): boolean {\n  return e instanceof Error && e.message === 'terminal_pane_owner_unverified'\n}","tryCatchPattern":"try {\n  await attachStablePaneOwner(ctx)\n} catch (e) {\n  if (e instanceof Error && e.message === 'terminal_pane_owner_unverified') {\n    // pane cannot be reattached — create a fresh session instead of retrying\n    await spawnFreshPty(ctx)\n  } else throw e\n}","preventionTips":["Do not retry the attach on this error — the daemon cannot verify ownership, so retrying will not help.","After a daemon restart, expect stable panes to be unverifiable; create new sessions.","Track the daemon incarnation id so the UI can proactively offer a fresh terminal when the host changes."],"tags":["terminal","pty","daemon","session-ownership","reattach"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}