{"record":{"id":"290de5a8cdb357ce","repo":"stablyai/orca","slug":"failed-to-start-download","errorCode":null,"errorMessage":"Failed to start download","messagePattern":"Failed to start download","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/src/dictation/mobile-dictation-setup.ts","lineNumber":64,"sourceCode":"  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}\n\nexport async function downloadDictationModel(\n  client: Pick<RpcClient, 'sendRequest'>,\n  modelId: string\n): Promise<void> {\n  const response = await client.sendRequest('speech.models.download', { modelId })\n  if (!response.ok) {\n    throw new Error(response.error?.message || 'Failed to start download')\n  }\n}\n\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> {","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/dictation/mobile-dictation-setup.ts#L46-L82","documentation":"Fallback error from downloadDictationModel when speech.models.download fails and the host returned no error.message. The download RPC is fire-and-authoritative — failure means the host could not start fetching/extracting the requested model.","triggerScenarios":"client.sendRequest('speech.models.download', { modelId }) returns {ok:false} with no message; common causes: unknown modelId, host filesystem full, network blocked from the model CDN, model already mid-download with a different status, host lacking write permission to the model directory.","commonSituations":"User taps download for a model the desktop catalog no longer lists; the host's model cache directory is read-only; the CDN mirror is unreachable from the desktop; a previous extraction left a partial file blocking restart.","solutions":["Re-run fetchDictationSetup to confirm modelId still exists in setup.models with status 'available' before retrying the download.","Inspect desktop host logs for the speech.models.download failure cause (disk space, permissions, network).","If a previous download stalled, call deleteDictationModel(modelId) to clear partial state before re-downloading.","Retry once after a short delay — transient CDN/network errors are common."],"exampleFix":"// before\nconst response = await client.sendRequest('speech.models.download', { modelId })\nif (!response.ok) {\n  throw new Error(response.error?.message || 'Failed to start download')\n}\n\n// after — surface the host code so the UI can distinguish 'already downloading'\nif (!response.ok) {\n  const code = response.error?.code\n  if (code === 'already_downloading') return\n  throw new Error(response.error?.message || `Failed to start download${code ? ` (${code})` : ''}`)\n}","handlingStrategy":"try-catch","validationCode":"// Confirm the model is in the catalog and not already in flight\nconst setup = await fetchDictationSetup(client)\nconst model = setup.models.find((m) => m.id === modelId)\nif (!model) throw new Error('Unknown model')\nif (isModelInFlight(model)) return // already downloading","typeGuard":"function isDownloadStartError(err: unknown): boolean {\n  return err instanceof Error && err.message === 'Failed to start download'\n}","tryCatchPattern":"try {\n  await downloadDictationModel(client, modelId)\n} catch (err) {\n  if (isDownloadStartError(err)) {\n    showDownloadFailedToast(modelId)\n    return\n  }\n  throw err\n}","preventionTips":["Refresh fetchDictationSetup before each download attempt to catch catalog drift.","Clear partial downloads via deleteDictationModel before retrying after a stall.","Show download progress so users do not re-tap and race the in-flight download."],"tags":["rpc","dictation","download","speech","typescript"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}