{"record":{"id":"e2500d411e1d1de1","repo":"stablyai/orca","slug":"update-the-paired-desktop-orca-app-to-use-mobile-v","errorCode":null,"errorMessage":"Update the paired desktop Orca app to use mobile voice settings.","messagePattern":"Update the paired desktop Orca app to use mobile voice settings\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/src/dictation/mobile-dictation-setup.ts","lineNumber":38,"sourceCode":"): boolean {\n  const message = error?.message ?? ''\n  return (\n    message.includes('speech.models.list') &&\n    (error?.code === 'method_not_found' || message.includes('not available to mobile clients'))\n  )\n}\n\nexport function isDictationSetupRequiredError(message: string): boolean {\n  return SETUP_REQUIRED_CODES.has(message) || message.startsWith('voice_model_not_ready:')\n}\n\nexport async function fetchDictationSetup(\n  client: Pick<RpcClient, 'sendRequest'>\n): Promise<MobileSpeechSetup> {\n  const response = await fetchDictationSetupResponse(client)\n  if (!response.ok) {\n    if (isLegacyDesktopSpeechSetupError(response.error)) {\n      throw new Error(LEGACY_DESKTOP_SPEECH_SETUP_MESSAGE)\n    }\n    throw new Error(response.error?.message || 'Failed to load dictation models')\n  }\n  return (response as RpcSuccess).result as MobileSpeechSetup\n}\n\nasync function fetchDictationSetupResponse(client: Pick<RpcClient, 'sendRequest'>) {\n  try {\n    return await client.sendRequest('speech.models.list', null)\n  } catch (error) {\n    if (!(error instanceof LogicalClientCutoverError)) {\n      throw error\n    }\n    // Why: this read can safely repeat on the authenticated replacement; mutation\n    // RPCs must still surface cutover so callers never replay unknown commits.\n    return client.sendRequest('speech.models.list', null)\n  }\n}","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/dictation/mobile-dictation-setup.ts#L20-L56","documentation":"Mapped error from fetchDictationSetup when the paired desktop runtime is too old to know about the mobile speech API. isLegacyDesktopSpeechSetupError fires when the error message references speech.models.list AND the code is method_not_found (or the message says 'not available to mobile clients'). Rather than leak the raw denial, the client surfaces an upgrade instruction.","triggerScenarios":"client.sendRequest('speech.models.list', null) fails because the desktop host returns method_not_found for speech.models.list (the method predates the desktop build), or returns a message containing 'not available to mobile clients'. The mobile app is paired against an older Orca desktop that does not implement the speech.models.* allowlist.","commonSituations":"User upgraded the mobile app but not the desktop app; user paired against a desktop running a pre-speech-runtime build; the desktop's speech capability flag is off but the build is new enough to deny explicitly.","solutions":["Prompt the user to update the paired Orca desktop to a build that implements speech.models.list / speech.models.download / speech.models.delete / speech.dictation.setup.","After the desktop updates, re-pair or reconnect the host so the capability negotiation re-runs, then call fetchDictationSetup again.","If updating is not possible, disable the dictation entry point on that host via isLegacyDesktopSpeechSetupError so users do not hit a dead-end toast."],"exampleFix":"// before — caller shows raw error\ntry { await fetchDictationSetup(client) } catch (e) { showError(e.message) }\n\n// after — caller maps the legacy message to upgrade UX\ntry {\n  await fetchDictationSetup(client)\n} catch (e) {\n  if (e.message === LEGACY_DESKTOP_SPEECH_SETUP_MESSAGE) {\n    openDesktopUpgradeSheet()\n  } else {\n    showError(e.message)\n  }\n}","handlingStrategy":"validation","validationCode":"// Probe capability before calling fetchDictationSetup\nconst status = await client.sendRequest('status.get', undefined)\nif (!status.ok || !(status as any).result?.capabilities?.speech) {\n  showDesktopUpgradePrompt()\n  return\n}","typeGuard":"function isLegacyDesktopSpeechError(err: unknown): boolean {\n  return err instanceof Error && err.message === 'Update the paired desktop Orca app to use mobile voice settings.'\n}","tryCatchPattern":"try {\n  await fetchDictationSetup(client)\n} catch (err) {\n  if (isLegacyDesktopSpeechError(err)) {\n    openDesktopUpgradeSheet()\n    return\n  }\n  throw err\n}","preventionTips":["Advertise the required desktop build version in the mobile release notes; gate the dictation UI on status.get capability if available.","Cache the legacy-desktop finding per host so repeated taps do not re-round-trip speech.models.list.","When pairing a new host, run a capability probe and disable the mic entry point if speech is unsupported."],"tags":["rpc","dictation","version-compat","speech","typescript"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}