stablyai/orca · warning

Not connected: ${method}

Error message

Not connected: ${method}

What it means

Thrown by sendRequest in rpc-client.ts (line 980-982) when the caller passed options.failWhenDisconnected:true AND the connection state is not 'connected' at call time. This is the fail-fast opt-in: by default sendRequest parks in waitForConnected and waits for a reconnect (replaying the request after), but interactive PTY writes (terminal bytes, composer sends) set failWhenDisconnected because a stale byte replayed after a 30s reconnect corrupts the terminal. The thrown method name identifies which RPC was refused.

Source

Thrown at mobile/src/transport/rpc-client.ts:981

    registerPending: (id, onSettled) => pending.set(id, { resolve: onSettled, reject: onSettled }),
    clearPending: (id) => pending.delete(id),
    sendProbe: (id) => sendEncrypted({ id, deviceToken, method: 'status.get' }),
    forceReconnect: closeAndSynthesize
  })

  openConnection()

  return {
    async sendRequest(
      method: string,
      params?: unknown,
      options?: SendRequestOptions
    ): Promise<RpcResponse> {
      const budget = openRpcRequestBudget(options)
      const waitStart = budget.startedAt
      const wasConnected = state === 'connected'
      if (options?.failWhenDisconnected && !wasConnected) {
        throw new Error(`Not connected: ${method}`)
      }
      await waitForConnected(options?.timeoutMs)
      if (!wasConnected) {
        console.log('[net] sendRequest waited for connect', {
          method,
          waitedMs: Date.now() - waitStart
        })
      }

      return new Promise((resolve, reject) => {
        const id = nextId()
        const timeoutMs = resolvePostConnectRequestTimeout(budget, REQUEST_TIMEOUT_MS)
        const timeout = setTimeout(() => {
          pending.delete(id)
          console.log('[net] sendRequest TIMEOUT', {
            method,
            timeoutMs,
            state

View on GitHub (pinned to 1136503c6a)

Solutions

  1. If the call is idempotent/non-interactive, remove failWhenDisconnected to let it wait for reconnect.
  2. If interactive, surface 'Reconnecting…' to the user and queue the input locally for re-send once onStateChange reports 'connected'.
  3. Check client.getState() before calling — if not 'connected', decide wait-vs-fail explicitly rather than relying on the option.
  4. Subscribe to client.onStateChange to gate interactive sends on the connected state.

Example fix

// before — interactive send fails fast on disconnect
await client.sendRequest('terminal.write', bytes, { failWhenDisconnected: true })

// after — gate on connection state, queue while disconnected
if (client.getState() !== 'connected') {
  pendingWrites.push(bytes) // replayed on 'connected' state change
  return
}
await client.sendRequest('terminal.write', bytes)
Defensive patterns

Strategy: validation

Validate before calling

// Before sendRequest with failWhenDisconnected, check state
function canSendNow(client: RpcClient): boolean {
  return client.getState() === 'connected'
}
// usage:
if (options.failWhenDisconnected && !canSendNow(client)) {
  // queue or surface 'reconnecting' instead of letting sendRequest throw
  pendingWrites.push({ method, params })
  return
}

Type guard

function isNotConnectedError(error: unknown): boolean {
  return error instanceof Error && /^Not connected: /.test(error.message)
}

Try / catch

try {
  await client.sendRequest(method, params, { failWhenDisconnected: true })
} catch (error) {
  if (isNotConnectedError(error)) {
    pendingWrites.push({ method, params })
    client.onStateChange(function listener(state) {
      if (state === 'connected') {
        client.onStateChange.removeListener?.(listener)
        void flushPending()
      }
    })
    return
  }
  throw error
}

Prevention

When it happens

Trigger: client.sendRequest(method, params, { failWhenDisconnected: true }) called while state ∈ {'connecting','handshaking','disconnected','reconnecting','auth-failed'}. Most commonly: terminal write paths, composer 'send' loops, or any caller that sized its semantics against immediate delivery rather than eventual delivery.

Common situations: Connection dropped mid-session (network blip, app backgrounded, desktop asleep) and the terminal/composer attempted to write. Without failWhenDisconnected these would hang on waitForConnected (up to options.timeoutMs or the GIVE_UP_AFTER_ATTEMPTS cap) and then replay — for interactive input that's worse than failing fast.

Related errors


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