stablyai/orca · error

${RPC error message}

Error message

${RPC error message}

What it means

Thrown by requestResult, the internal helper used by captureMobileFileMutationOwnership for status.get, worktree.show, and ssh.getState. Any of those RPCs returning {ok:false} re-throws the host's error message verbatim. The 15s timeout (FILE_MUTATION_TIMEOUT_MS) means transport hangs also surface here as errors.

Source

Thrown at mobile/src/files/mobile-file-mutation-ownership.ts:78

      ? (
          await requestResult<{ state: SshConnectionState | null }>(client, 'ssh.getState', {
            targetId: host.targetId
          })
        ).state
      : null
  return buildMobileFileMutationOwnership(result.worktree.hostId, sshState)
}

async function requestResult<TResult>(
  client: Pick<RpcClient, 'sendRequest'>,
  method: string,
  params: unknown
): Promise<TResult> {
  const response = await client.sendRequest(method, params, {
    timeoutMs: FILE_MUTATION_TIMEOUT_MS
  })
  if (!response.ok) {
    throw new Error((response as RpcFailure).error.message)
  }
  return (response as RpcSuccess).result as TResult
}

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Identify which of the three RPCs failed by wrapping each call site or inspecting the host log; the message is the host's, so it usually names the method.
  2. On transport/timeout errors, forceReconnect the host and retry captureMobileFileMutationOwnership once.
  3. On method_not_found for status.get, the desktop build is too old to support the file-mutation capability check — upgrade the desktop.
  4. On ssh.getState failure with the target gone, prompt the user to reconfigure the SSH target.

Example fix

// before
async function requestResult<TResult>(client, method, params): Promise<TResult> {
  const response = await client.sendRequest(method, params, { timeoutMs: FILE_MUTATION_TIMEOUT_MS })
  if (!response.ok) {
    throw new Error((response as RpcFailure).error.message)
  }
  return (response as RpcSuccess).result as TResult
}

// after — tag the failing method so the surfaced error is diagnosable
async function requestResult<TResult>(client, method, params): Promise<TResult> {
  const response = await client.sendRequest(method, params, { timeoutMs: FILE_MUTATION_TIMEOUT_MS })
  if (!response.ok) {
    const code = (response as RpcFailure).error?.code
    throw new Error(`${method} failed${code ? ` [${code}]` : ''}: ${(response as RpcFailure).error.message}`)
  }
  return (response as RpcSuccess).result as TResult
}
Defensive patterns

Strategy: retry

Validate before calling

// Confirm the three RPCs the helper uses are likely to succeed
if (connState !== 'connected') throw new Error('Host not connected')

Type guard

function isFileMutationRpcTransient(err: unknown): boolean {
  if (!(err instanceof Error)) return false
  const m = err.message.toLowerCase()
  return m.includes('timeout') || m.includes('disconnected') || m.includes('temporarily')
}

Try / catch

try {
  return await captureMobileFileMutationOwnership(client, worktree)
} catch (err) {
  if (isFileMutationRpcTransient(err)) {
    await forceReconnect()
    return await captureMobileFileMutationOwnership(client, worktree)
  }
  throw err
}

Prevention

When it happens

Trigger: client.sendRequest(method, params, {timeoutMs: 15000}) returns {ok:false} for one of: 'status.get' (host capability query), 'worktree.show' (hostId lookup), or 'ssh.getState' (connection generation lookup). Common codes: timeout, disconnected, method_not_found, permission_denied, internal_error.

Common situations: status.get fails because the host is mid-cutover; worktree.show times out on a slow link; ssh.getState fails because the SSH target was deleted between capture and query; the host is overloaded and pushes one of these reads past 15s.

Related errors


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