stablyai/orca · info · TerminalAttachCanceledError
Attach canceled for session ${sessionId}
Error message
Attach canceled for session ${sessionId} What it means
preparePtySpawnUnlessCanceled registers a per-session preparation record before the async preparePtySpawn() probe, so a concurrent close can flip preparation.canceled before a subprocess is created. If canceled is true after the probe resolves, it throws TerminalAttachCanceledError(sessionId) — the create was aborted to avoid spawning a PTY the user already closed.
Source
Thrown at src/main/daemon/daemon-server.ts:902
timer.unref()
socket.once('close', start)
socket.once('error', start)
this.pendingShutdownReplies.set(key, { start })
}
private async preparePtySpawnUnlessCanceled(sessionId: string, clientId: string): Promise<void> {
const preparation: PendingPtySpawnPreparation = {
canceled: false,
clientId
}
const pending = this.pendingPtySpawnPreparations.get(sessionId) ?? new Set()
pending.add(preparation)
this.pendingPtySpawnPreparations.set(sessionId, pending)
try {
// Why: register before the async probe so a concurrent close can cancel this creation before a subprocess exists.
await this.preparePtySpawn()
if (preparation.canceled) {
throw new TerminalAttachCanceledError(sessionId)
}
} finally {
pending.delete(preparation)
if (pending.size === 0) {
this.pendingPtySpawnPreparations.delete(sessionId)
}
}
}
private cancelPendingPtySpawnPreparations(sessionId: string): boolean {
const pending = this.pendingPtySpawnPreparations.get(sessionId)
if (!pending) {
return false
}
for (const preparation of pending) {
preparation.canceled = true
}
return trueView on GitHub (pinned to 1136503c6a)
Solutions
- Treat TerminalAttachCanceledError as benign — the session was closed by the user/caller before spawn; do not surface as a crash.
- Avoid issuing createOrAttach for a sessionId the UI has already torn down; track in-flight tabs.
- If it fires constantly, audit the renderer for open/close thrash on the same id.
Defensive patterns
Strategy: try-catch
Type guard
import { TerminalAttachCanceledError } from './daemon-errors'
function isAttachCanceled(e: unknown): e is TerminalAttachCanceledError {
return e instanceof TerminalAttachCanceledError
} Try / catch
try {
await host.createOrAttach({ sessionId, attachOnly: false, ... })
} catch (e) {
if (isAttachCanceled(e)) {
// benign — closed before spawn; suppress
} else throw e
} Prevention
- Track in-flight terminal tabs and do not issue createOrAttach for ids the UI has torn down.
- Treat TerminalAttachCanceledError as benign in telemetry — do not count as a crash.
- Debounce renderer remount churn to avoid open/close thrash on the same id.
When it happens
Trigger: createOrAttach (attachOnly=false) running while the renderer closes the same session id; close arrives between probe registration and the spawn; rapid open/close thrash on a terminal tab.
Common situations: User opens then immediately closes a terminal; a reconnect race that reissues create then cancels; UI remount churn driving attach/cancel cycles.
Related errors
- terminal_gone
- [plain-node-entry-guard] could not smoke-load daemon-entry.j
- [verify-packaged-daemon-entry] could not launch daemon-entry
- Daemon PTY "${id}" is awaiting recovery
- agent_session_ownership_unknown
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/40d1800baecdd1f1.
Report an issue: GitHub.