{"record":{"id":"254e9da2bb94ffff","repo":"stablyai/orca","slug":"rpc-error-message","errorCode":null,"errorMessage":"${RPC error message}","messagePattern":"\\$\\{RPC error message\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mobile/src/files/mobile-file-mutation-ownership.ts","lineNumber":78,"sourceCode":"      ? (\n          await requestResult<{ state: SshConnectionState | null }>(client, 'ssh.getState', {\n            targetId: host.targetId\n          })\n        ).state\n      : null\n  return buildMobileFileMutationOwnership(result.worktree.hostId, sshState)\n}\n\nasync function requestResult<TResult>(\n  client: Pick<RpcClient, 'sendRequest'>,\n  method: string,\n  params: unknown\n): Promise<TResult> {\n  const response = await client.sendRequest(method, params, {\n    timeoutMs: FILE_MUTATION_TIMEOUT_MS\n  })\n  if (!response.ok) {\n    throw new Error((response as RpcFailure).error.message)\n  }\n  return (response as RpcSuccess).result as TResult\n}\n","sourceCodeStart":60,"sourceCodeEnd":82,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/files/mobile-file-mutation-ownership.ts#L60-L82","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","On transport/timeout errors, forceReconnect the host and retry captureMobileFileMutationOwnership once.","On method_not_found for status.get, the desktop build is too old to support the file-mutation capability check — upgrade the desktop.","On ssh.getState failure with the target gone, prompt the user to reconfigure the SSH target."],"exampleFix":"// before\nasync function requestResult<TResult>(client, method, params): Promise<TResult> {\n  const response = await client.sendRequest(method, params, { timeoutMs: FILE_MUTATION_TIMEOUT_MS })\n  if (!response.ok) {\n    throw new Error((response as RpcFailure).error.message)\n  }\n  return (response as RpcSuccess).result as TResult\n}\n\n// after — tag the failing method so the surfaced error is diagnosable\nasync function requestResult<TResult>(client, method, params): Promise<TResult> {\n  const response = await client.sendRequest(method, params, { timeoutMs: FILE_MUTATION_TIMEOUT_MS })\n  if (!response.ok) {\n    const code = (response as RpcFailure).error?.code\n    throw new Error(`${method} failed${code ? ` [${code}]` : ''}: ${(response as RpcFailure).error.message}`)\n  }\n  return (response as RpcSuccess).result as TResult\n}","handlingStrategy":"retry","validationCode":"// Confirm the three RPCs the helper uses are likely to succeed\nif (connState !== 'connected') throw new Error('Host not connected')","typeGuard":"function isFileMutationRpcTransient(err: unknown): boolean {\n  if (!(err instanceof Error)) return false\n  const m = err.message.toLowerCase()\n  return m.includes('timeout') || m.includes('disconnected') || m.includes('temporarily')\n}","tryCatchPattern":"try {\n  return await captureMobileFileMutationOwnership(client, worktree)\n} catch (err) {\n  if (isFileMutationRpcTransient(err)) {\n    await forceReconnect()\n    return await captureMobileFileMutationOwnership(client, worktree)\n  }\n  throw err\n}","preventionTips":["Tag the failing method in the error message (e.g., 'ssh.getState failed: ...') so callers can react.","Keep FILE_MUTATION_TIMEOUT_MS at 15s — too short truncates slow SSH reads, too long blocks the UI.","Re-capture ownership on a new connectionGeneration; never reuse a token across reconnects."],"tags":["rpc","file-mutation","timeout","ssh","typescript"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}