{"record":{"id":"7be3cbb00ff21a9e","repo":"stablyai/orca","slug":"failed-to-start-microphone-recording","errorCode":null,"errorMessage":"Failed to start microphone recording","messagePattern":"Failed to start microphone recording","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mobile/src/hooks/mobile-dictation-desktop-start.ts","lineNumber":118,"sourceCode":"    keepAwakeOwner\n      .acquire(dictationId)\n      .catch((err: unknown) => console.error('Keep-awake activation failed', err))\n      .finally(() => {\n        clearTimeout(budgetTimer)\n        resolve()\n      })\n  })\n\n  if (!isCurrentStart(options)) {\n    await cancelStaleStart(options, { releaseKeepAwake: true })\n    return false\n  }\n\n  try {\n    // Commit in the same continuation as the final stale check; returning first\n    // would let a queued cancel resurrect microphone recording after cleanup.\n    if (!options.commitRecordingStart()) {\n      throw new Error('Failed to start microphone recording')\n    }\n  } catch (err) {\n    const wasCurrent = isCurrentStart(options)\n    // Native recording can partially start before throwing, so stop audio before\n    // releasing the wake tag and remote session.\n    try {\n      options.rollbackRecordingStart()\n    } catch {\n      // Continue releasing independently owned resources after native audio failure.\n    }\n    options.clearActiveId(dictationId)\n    await Promise.allSettled([\n      keepAwakeOwner.release(dictationId),\n      client.sendRequest('speech.dictation.cancel', { dictationId })\n    ])\n    const shouldReport = wasCurrent && canReportStartFailure(options)\n    setIdleIfGenerationCurrent(options)\n    if (!shouldReport) {","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/hooks/mobile-dictation-desktop-start.ts#L100-L136","documentation":"Thrown by startMobileDictationDesktopSession when options.commitRecordingStart() returned false. commitRecordingStart (provided by use-mobile-dictation.ts) returns false when the native toggleRecording(true) call did not succeed — i.e., the device-level microphone recording could not actually start. The surrounding catch rolls back any partial native audio state and cancels the remote session.","triggerScenarios":"options.commitRecordingStart() returns false. In use-mobile-dictation.ts this happens when toggleRecording(true) (from @orca/expo-two-way-audio) returns false: the native audio module refused to start capture. Causes: another app holds the mic, the audio session category is wrong, the native module threw and was caught, hardware mic unavailable.","commonSituations":"Another app (Calls, Voice Memos) is holding the microphone on iOS; Android audio focus was denied; the native audio module was not initialized (initialize() returned true but the recorder still failed); a previous session left the recorder in a bad state.","solutions":["Guarantee tearDown() / toggleRecording(false) ran before attempting a new start — call cancel() to fully reset native audio first.","Confirm no other app is using the microphone (have the user close other audio apps).","Verify the native module @orca/expo-two-way-audio is linked and its audio session category is configured for record-only on iOS.","If commitRecordingStart keeps returning false on a device, file a native-audio bug with the recorder's error log."],"exampleFix":"// before — startMobileDictationDesktopSession\nif (!options.commitRecordingStart()) {\n  throw new Error('Failed to start microphone recording')\n}\n\n// after — capture the native recorder's reason so the UI can guide the user\nconst reason = options.lastRecordingStartFailure?.() \nif (!options.commitRecordingStart()) {\n  throw new Error(reason ? `Failed to start microphone recording: ${reason}` : 'Failed to start microphone recording')\n}","handlingStrategy":"validation","validationCode":"// Ensure native audio is in a clean state before committing start\nawait tearDown()\nconst initialized = await initialize()\nif (!initialized) throw new Error('Native audio failed to initialize')","typeGuard":"function isMicrophoneStartError(err: unknown): boolean {\n  return err instanceof Error && err.message === 'Failed to start microphone recording'\n}","tryCatchPattern":"try {\n  return await startMobileDictationDesktopSession(options)\n} catch (err) {\n  if (isMicrophoneStartError(err)) {\n    showError('Microphone unavailable. Close other audio apps and try again.')\n    return false\n  }\n  throw err\n}","preventionTips":["Always tearDown() before a fresh start to release any half-open recorder.","Detect competing audio apps and ask the user to close them before retrying.","Surface the native module's failure reason via commitRecordingStart so users get actionable copy."],"tags":["dictation","native-audio","speech","microphone","typescript"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}