{"record":{"id":"5303f115a39003f0","repo":"stablyai/orca","slug":"unable-to-reach-host","errorCode":null,"errorMessage":"Unable to reach host","messagePattern":"Unable to reach host","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/src/agent-history/use-mobile-agent-history-state.ts","lineNumber":96,"sourceCode":"          // (connState flips re-run the load effect) instead of tearing it\n          // down to a full-screen error, matching the host list screen.\n          setScreenState((prev) =>\n            prev.kind === 'ready' ? prev : { kind: 'error', message: 'Waiting for host…' }\n          )\n        }\n        return\n      }\n\n      setScreenState((prev) => (prev.kind === 'ready' ? prev : { kind: 'loading' }))\n      try {\n        // Gate on the capability so older hosts lacking the method are detected\n        // and we never call a missing RPC.\n        const statusResponse = await client.sendRequest('status.get')\n        if (!isCurrent()) {\n          return\n        }\n        if (!statusResponse.ok) {\n          throw new Error(statusResponse.error?.message || 'Unable to reach host')\n        }\n        const status = (statusResponse as RpcSuccess).result as StatusWithCapabilities\n        setHostStatusResult(status)\n        if (!status.capabilities?.includes(MOBILE_AI_VAULT_CAPABILITY)) {\n          setScreenState({ kind: 'unsupported' })\n          return\n        }\n\n        // Why: a scoped tab needs the active worktree's path to narrow. Until the\n        // worktree list has loaded, hold loading rather than firing an unscoped\n        // fetch that would briefly show unrelated host history. Once loaded we\n        // proceed even if the worktree isn't found, to avoid a stuck spinner.\n        if (options.scope !== 'all' && !activeWorktree && !worktreesLoaded) {\n          if (isCurrent()) {\n            setScreenState((prev) => (prev.kind === 'ready' ? prev : { kind: 'loading' }))\n          }\n          return\n        }","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/agent-history/use-mobile-agent-history-state.ts#L78-L114","documentation":"Capability-gating error in the mobile agent-history hook: it calls `status.get` first to (a) confirm the host is reachable and (b) read capabilities before attempting the AI-vault-specific RPC. If status.get returns ok=false and the host supplied no message, this generic 'Unable to reach host' is thrown and surfaces as an error screen state.","triggerScenarios":"status.get RPC fails (transport down, host process crashed, version too old to implement status.get), or returns ok=false with an empty error.message. An isCurrent() guard short-circuits if the request became stale.","commonSituations":"Host went offline between screen mount and the status probe, an SSH relay disconnect, an older host that predates status.get, or a firewall/network issue blocking the RPC channel.","solutions":["Verify the Orca host is running and reachable (check the connection/relay).","Retry — the hook sets an error screen state and the user can pull to refresh.","Upgrade an old host that lacks status.get.","Inspect the host logs for the underlying status.get failure reason."],"exampleFix":"// before\nif (!statusResponse.ok) {\n  throw new Error(statusResponse.error?.message || 'Unable to reach host')\n}\n\n// after — distinguish transport failure from explicit host error\nif (!statusResponse.ok) {\n  const detail = statusResponse.error?.message\n  throw new Error(detail ? `Host unreachable: ${detail}` : 'Unable to reach host')\n}","handlingStrategy":"try-catch","validationCode":"// Cheap liveness probe before status.get\n// (the hook already does status.get; just ensure the client is connected)\nif (!client?.connected) { setScreenState({ kind: 'error', message: 'Not connected' }); return }","typeGuard":"function isStatusSuccess(r: RpcSuccess | RpcFailure): r is RpcSuccess & { result: StatusWithCapabilities } {\n  return r.ok\n}","tryCatchPattern":"try {\n  const statusResponse = await client.sendRequest('status.get')\n  if (!isCurrent()) return\n  if (!statusResponse.ok) throw new Error(statusResponse.error?.message || 'Unable to reach host')\n} catch (err) {\n  if (!isCurrent()) return\n  setScreenState({ kind: 'error', message: (err as Error).message })\n}","preventionTips":["Use the isCurrent() stale-guard on every async checkpoint.","Retry on transient transport errors via a pull-to-refresh.","Detect METHOD_NOT_FOUND to show 'unsupported' rather than 'error'."],"tags":["mobile","rpc","status","capability-gate","fallback-message"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}