stablyai/orca · error

Terminal host is shutting down

Error message

Terminal host is shutting down

What it means

createOrAttachTerminalSession refuses a new session when deps.creationFenced is true. The terminal host sets the fence during shutdown/teardown so no new sessions can be spawned while it is draining. This prevents a session from being created that would immediately need to be torn down, and keeps the shutdown path deterministic.

Source

Thrown at src/main/daemon/terminal-host-session-create.ts:31

import { resolveWslSessionContext } from './wsl-session-context'

type TerminalHostSessionCreateDependencies = {
  sessions: Map<string, Session>
  sessionTeardown: TerminalSessionTeardown
  killedTombstones: TerminalHostTombstones
  spawnSubprocess: TerminalHostOptions['spawnSubprocess']
  creationFenced: boolean
  onDeadSessionRemoved: (sessionId: string) => void
  onSessionCreated: (sessionId: string, generation: string | undefined, isAlive: boolean) => void
  onSessionExit: (sessionId: string, generation: string | undefined) => void
}

export async function createOrAttachTerminalSession(
  opts: InternalCreateOrAttachOptions,
  deps: TerminalHostSessionCreateDependencies
): Promise<CreateOrAttachResult> {
  if (deps.creationFenced) {
    throw new Error('Terminal host is shutting down')
  }
  opts.onSessionResolved?.(opts.sessionId)
  const existing = deps.sessions.get(opts.sessionId)

  // Why: descendant capture must finish before attach or recreation, or the
  // caller could receive a doomed session while teardown owns its process.
  if (deps.sessionTeardown.get(opts.sessionId) || existing?.isTerminating) {
    throw new SessionNotFoundError(opts.sessionId)
  }

  if (existing && existing.isAlive && !existing.isTerminating) {
    const snapshot = existing.getSnapshot()
    existing.detachAllClients()
    const token = existing.attachClient(opts.streamClient)
    return {
      isNew: false,
      snapshot,
      pid: existing.pid,

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Do not issue create requests to a host that is shutting down; check host liveness before creating.
  2. On the client, treat this as a transient/reconnect condition: wait for a fresh host or reconnect to a new daemon, then retry.
  3. Ensure shutdown drains in-flight creates before fencing if orderly completion matters.
  4. Cancel pending create requests when shutdown is initiated rather than letting them hit the fence.
Defensive patterns

Strategy: retry

Type guard

function isHostShuttingDown(e: unknown): boolean {
  return e instanceof Error && e.message === 'Terminal host is shutting down'
}

Try / catch

try {
  return await createOrAttachTerminalSession(opts, deps)
} catch (e) {
  if (e instanceof Error && e.message === 'Terminal host is shutting down') {
    // reconnect to a fresh host/daemon, then retry
    await reconnectHost()
    return await createOrAttachTerminalSession(opts, freshDeps)
  }
  throw e
}

Prevention

When it happens

Trigger: createOrAttachTerminalSession called after the host began shutting down and set creationFenced = true. Any create (non-attach) during host disposal hits this.

Common situations: A createOrAttach racing the app quit / daemon shutdown; the host fencing during an error-driven teardown while a queued create is still in flight; retries of createOrAttach after shutdown has begun.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/77546d353efb27b8. Report an issue: GitHub.