{"record":{"id":"1832cf07c4083095","repo":"stablyai/orca","slug":"failed-to-delete-model","errorCode":null,"errorMessage":"Failed to delete model","messagePattern":"Failed to delete model","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/src/dictation/mobile-dictation-setup.ts","lineNumber":74,"sourceCode":"}\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> {\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'","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/dictation/mobile-dictation-setup.ts#L56-L92","documentation":"Fallback error from deleteDictationModel when speech.models.delete fails and the host returned no error.message. Deletion is supposed to be idempotent on the host, so a real failure typically means the model file is locked, missing in a way the host refuses, or the host cannot update its catalog.","triggerScenarios":"client.sendRequest('speech.models.delete', { modelId }) returns {ok:false} with no message; causes: modelId not in catalog, model file locked by an active dictation session, host lacks delete permission, model is currently selected and the host refuses to delete the active model.","commonSituations":"User tries to delete the currently selected model without first switching selection; a dictation session is running and holds the file open; the host catalog got out of sync with disk.","solutions":["Ensure no dictation session is active (status is idle) before deleting — stop any in-flight session first.","If the model is the selectedModelId, call setDictationConfig to pick a different model (or disable) before deleting.","Refresh setup via fetchDictationSetup to confirm the modelId is still listed; if it is already gone, treat as success.","Check host permissions on the model cache directory."],"exampleFix":"// before\nconst response = await client.sendRequest('speech.models.delete', { modelId })\nif (!response.ok) {\n  throw new Error(response.error?.message || 'Failed to delete model')\n}\n\n// after — treat already-gone as success\nif (!response.ok) {\n  const code = response.error?.code\n  if (code === 'not_found') return (await fetchDictationSetup(client))\n  throw new Error(response.error?.message || 'Failed to delete model')\n}","handlingStrategy":"try-catch","validationCode":"// Stop any active session and confirm the model is not selected\nif (dictationStatus !== 'idle') await cancelDictation()\nconst setup = await fetchDictationSetup(client)\nif (setup.selectedModelId === modelId) throw new Error('Cannot delete the selected model')","typeGuard":"function isDeleteModelError(err: unknown): boolean {\n  return err instanceof Error && err.message === 'Failed to delete model'\n}","tryCatchPattern":"try {\n  return await deleteDictationModel(client, modelId)\n} catch (err) {\n  if (isDeleteModelError(err)) {\n    showDeleteFailedToast(modelId)\n    return await fetchDictationSetup(client)\n  }\n  throw err\n}","preventionTips":["Never delete the currently selected model — switch selection first via setDictationConfig.","Treat 'not_found' as success since the desired state (model gone) is achieved.","Stop any active dictation session before deletion to release file locks."],"tags":["rpc","dictation","speech","file-management","typescript"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}