{"record":{"id":"2070a7ebdc03572f","repo":"stablyai/orca","slug":"failed-to-update-dictation-settings","errorCode":null,"errorMessage":"Failed to update dictation settings","messagePattern":"Failed to update dictation settings","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/src/dictation/mobile-dictation-setup.ts","lineNumber":85,"sourceCode":"\nexport async function deleteDictationModel(\n  client: Pick<RpcClient, 'sendRequest'>,\n  modelId: string\n): Promise<MobileSpeechSetup> {\n  const response = await client.sendRequest('speech.models.delete', { modelId })\n  if (!response.ok) {\n    throw new Error(response.error?.message || 'Failed to delete model')\n  }\n  return (response as RpcSuccess).result as MobileSpeechSetup\n}\n\nexport async function setDictationConfig(\n  client: Pick<RpcClient, 'sendRequest'>,\n  params: { enabled?: boolean; modelId?: string; dictationMode?: 'toggle' | 'hold' }\n): Promise<MobileSpeechSetup> {\n  const response = await client.sendRequest('speech.dictation.setup', params)\n  if (!response.ok) {\n    throw new Error(response.error?.message || 'Failed to update dictation settings')\n  }\n  return (response as RpcSuccess).result as MobileSpeechSetup\n}\n\n// A model is mid-download (or extracting) and the sheet should keep polling.\nexport function isModelInFlight(model: MobileSpeechModel): boolean {\n  return model.status === 'downloading' || model.status === 'extracting'\n}\n\n// Whether dictation can be used right now: enabled + a selected model that's ready.\nexport function isDictationReady(setup: MobileSpeechSetup): boolean {\n  if (!setup.enabled || !setup.selectedModelId) {\n    return false\n  }\n  const selected = setup.models.find((m) => m.id === setup.selectedModelId)\n  return selected?.status === 'ready'\n}\n","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/dictation/mobile-dictation-setup.ts#L67-L103","documentation":"Fallback error from setDictationConfig when speech.dictation.setup fails and the host returned no error.message. This RPC commits the user's enabled/modelId/dictationMode preferences, so a failure means the desktop refused to apply the new dictation configuration.","triggerScenarios":"client.sendRequest('speech.dictation.setup', params) returns {ok:false} with no message; causes: params.modelId does not reference a ready model, params.dictationMode is not in the host's allowed set on that build, host config write failed, the host is mid-cutover and rejected the mutation.","commonSituations":"User enables dictation and selects a model that is still 'downloading' or 'extracting'; user passes a dictationMode the desktop build does not support; the desktop's speech config file is read-only.","solutions":["Before calling setDictationConfig, confirm via fetchDictationSetup that modelId points to a model with status 'ready' (use isModelInFlight to gate).","Restrict dictationMode to the documented union ('toggle' | 'hold') and confirm the host build advertises both.","Retry once after reconnecting if the failure looks transport-related; persist the intended config locally so it can be re-applied.","Inspect desktop logs for the underlying config write failure."],"exampleFix":"// before\nconst response = await client.sendRequest('speech.dictation.setup', params)\nif (!response.ok) {\n  throw new Error(response.error?.message || 'Failed to update dictation settings')\n}\n\n// after — pre-validate model readiness\nconst setup = await fetchDictationSetup(client)\nif (params.modelId) {\n  const m = setup.models.find((x) => x.id === params.modelId)\n  if (!m || m.status !== 'ready') throw new Error('Selected model is not ready')\n}\nconst response = await client.sendRequest('speech.dictation.setup', params)\nif (!response.ok) {\n  throw new Error(response.error?.message || 'Failed to update dictation settings')\n}","handlingStrategy":"validation","validationCode":"// Pre-validate the modelId points to a ready model\nconst setup = await fetchDictationSetup(client)\nif (params.modelId) {\n  const m = setup.models.find((x) => x.id === params.modelId)\n  if (!m || m.status !== 'ready') throw new Error('Selected model is not ready')\n}\nif (params.dictationMode && !['toggle','hold'].includes(params.dictationMode)) {\n  throw new Error('Invalid dictation mode')\n}","typeGuard":"function isDictationConfigUpdateError(err: unknown): boolean {\n  return err instanceof Error && err.message === 'Failed to update dictation settings'\n}","tryCatchPattern":"try {\n  return await setDictationConfig(client, params)\n} catch (err) {\n  if (isDictationConfigUpdateError(err)) {\n    showConfigUpdateFailedToast()\n    return await fetchDictationSetup(client)\n  }\n  throw err\n}","preventionTips":["Always pass a ready model's id; gate the UI on isModelInFlight returning false.","Restrict dictationMode to the documented union; do not let arbitrary strings reach the RPC.","Persist the intended config locally so it can be re-applied after a transient host failure."],"tags":["rpc","dictation","speech","config","typescript"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}