stablyai/orca · error · SessionNotFoundError

Session not found: ${sessionId}

Error message

Session not found: ${sessionId}

What it means

SessionNotFoundError from attachDaemonOwnedSession: an attach-only adoption was attempted against the in-process fallback PTY provider (owner === fallback). By definition a fallback pty cannot own a daemon-surviving session, and its no-op attach would falsely report success while the stream stays blank. The attach is refused so the caller seeks the real daemon owner.

Source

Thrown at src/main/daemon/degraded-daemon-session-routing.ts:24

  sessionProviders: ReadonlyMap<string, IPtyProvider>,
  provider: IPtyProvider
): string[] {
  return [...sessionProviders]
    .filter(([, mappedProvider]) => mappedProvider === provider)
    .map(([id]) => id)
}

/** Attach-only session adoption: refuses the in-process fallback route. A
 *  fallback pty cannot own a daemon-surviving session by definition, and its
 *  no-op attach resolving would pin a subscriber-driven attach as succeeded
 *  while the stream stays blank. */
export async function attachDaemonOwnedSession(
  owner: IPtyProvider,
  fallback: IPtyProvider,
  sessionId: string
): ReturnType<IPtyProvider['attach']> {
  if (owner === fallback) {
    throw new SessionNotFoundError(sessionId)
  }
  return await owner.attach(sessionId)
}

/** Probes providers for an id absent from the routing map and adopts the
 *  first proven owner into the map. */
export function adoptOwningProvider(
  sessionProviders: Map<string, IPtyProvider>,
  providers: readonly IPtyProvider[],
  sessionId: string
): IPtyProvider | null {
  for (const provider of providers) {
    if (provider.hasPty?.(sessionId) === true) {
      sessionProviders.set(sessionId, provider)
      return provider
    }
  }
  return null

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Reconnect to the real daemon adapter and re-resolve the session owner before attaching.
  2. Do not mark daemon-owned session ids as owned by the fallback provider; keep the routing map accurate.
  3. If the daemon is permanently gone, create a fresh session rather than attach-adopting a fallback id.
  4. Validate that the resolved owner is not the fallback before calling attachDaemonOwnedSession.
Defensive patterns

Strategy: retry

Validate before calling

// Ensure the owner is a real daemon adapter, not the fallback, before attach-only
if (owner === fallback) {
  // reconnect to the daemon and re-resolve instead of attaching
  await reconnectDaemonAdapter()
}

Type guard

function isFallbackOwner(owner: IPtyProvider, fallback: IPtyProvider): boolean {
  return owner === fallback
}

Try / catch

try {
  return await attachDaemonOwnedSession(owner, fallback, sessionId)
} catch (e) {
  if (e instanceof SessionNotFoundError && owner === fallback) {
    const real = await resolveDaemonOwner(sessionId)
    return await attachDaemonOwnedSession(real, fallback, sessionId)
  }
  throw e
}

Prevention

When it happens

Trigger: attachDaemonOwnedSession(owner, fallback, sessionId) called where the session's route maps to the fallback provider (e.g., the daemon adapter is down and the session was degraded to the fallback), with attachOnly semantics.

Common situations: The daemon host is unavailable so sessions fell back to an in-process pty; an attach-only request arrives for one of those fallback sessions; a routing map pointing a daemon-surviving session id at the fallback provider.

Related errors


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