stablyai/orca · error · CodexAppServerTimeoutError

codex app-server session already timed out

Error message

codex app-server session already timed out

What it means

Thrown as CodexAppServerTimeoutError inside requestRpc when the session-wide deadline already fired (timedOut === true) before a new RPC call is made. The deadline timer sets timedOut and SIGKILLs the codex child; any subsequent requestRpc in the same session short-circuits with this message instead of writing into a dead pipe.

Source

Thrown at src/main/codex/codex-app-server-session.ts:233

  function notify(method: string, params?: Record<string, unknown>): void {
    const payload: Record<string, unknown> = { method }
    if (params !== undefined) {
      payload.params = params
    }
    try {
      sendLine(payload)
    } catch {
      // Notifications are fire-and-forget; a dead child fails the next request.
    }
  }

  async function requestRpc(method: string, params?: Record<string, unknown>): Promise<unknown> {
    if (spawnError) {
      throw spawnError
    }
    if (timedOut) {
      throw new CodexAppServerTimeoutError('codex app-server session already timed out')
    }
    if (exited) {
      throw buildEarlyExitError()
    }
    const id = nextRequestId++
    const response = await new Promise<JsonRpcResponse>((resolve, reject) => {
      pending.set(id, { resolve, reject })
      const payload: Record<string, unknown> = { method, id }
      if (params !== undefined) {
        payload.params = params
      }
      try {
        sendLine(payload)
      } catch (error) {
        pending.delete(id)
        reject(error instanceof Error ? error : new Error(String(error)))
      }
    })

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Raise invocation.timeoutMs to cover the total number of sequential RPCs the body performs (not just one).
  2. Reduce the number of sequential awaits in the session body, or batch work (e.g., one config/batchWrite instead of several).
  3. Profile each RPC to find the slow one and optimize the codex-side workload (fewer hooks, smaller config).
  4. Start a fresh session for additional work rather than reusing a timed-out one.
Defensive patterns

Strategy: validation

Validate before calling

// Design the session body to fit within the deadline; track elapsed budget:
const start = Date.now()
const withinBudget = () => Date.now() - start < invocation.timeoutMs - RESERVE_MS
// Structure the body so it stops issuing RPCs once withinBudget() is false.

Type guard

function isAlreadyTimedOutError(error: unknown): boolean {
  return error instanceof Error && error.message === 'codex app-server session already timed out'
}

Try / catch

try {
  await runCodexAppServerSession(invocation, async (rpc) => {
    // do all RPCs here; the session owns the deadline
  })
} catch (error) {
  if (isCodexAppServerTimeoutError(error)) {
    // start a fresh session with a larger timeoutMs rather than reusing
  }
}

Prevention

When it happens

Trigger: The body callback issued multiple sequential RPCs (initialize, hooks/list, config/batchWrite, hooks/list again) and an earlier await consumed the whole timeoutMs budget, so the next requestRpc sees timedOut already true; or the deadline fired during await and the next call detects it.

Common situations: A grant or heal body does several round-trips and the cumulative time exceeds invocation.timeoutMs; a slow first hooks/list eats the budget; the timeout was sized for fewer RPCs than the body performs.

Understand the failure class

Related errors


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