{"record":{"id":"ac3b5bbe89cb3a78","repo":"jamiepine/voicebox","slug":"microphone-access-is-not-available-please-ensure","errorCode":null,"errorMessage":"Microphone access is not available. Please ensure:\n1. The app has microphone permissions in System Settings (macOS: System Settings > Privacy & Security > Microphone)\n2. You restart the app after granting permissions\n3. You are using Tauri v2 with a webview that supports getUserMedia","messagePattern":"Microphone access is not available\\. Please ensure:\n1\\. The app has microphone permissions in System Settings \\(macOS: System Settings > Privacy & Security > Microphone\\)\n2\\. You restart the app after granting permissions\n3\\. You are using Tauri v2 with a webview that supports getUserMedia","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/src/lib/hooks/useAudioRecording.ts","lineNumber":57,"sourceCode":"      }\n\n      if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {\n        // Try waiting a bit for Tauri webview to initialize\n        await new Promise((resolve) => setTimeout(resolve, 100));\n\n        if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {\n          console.error('MediaDevices check:', {\n            hasNavigator: typeof navigator !== 'undefined',\n            hasMediaDevices: !!navigator?.mediaDevices,\n            hasGetUserMedia: !!navigator?.mediaDevices?.getUserMedia,\n            isTauri: platform.metadata.isTauri,\n          });\n\n          const errorMsg = platform.metadata.isTauri\n            ? 'Microphone access is not available. Please ensure:\\n1. The app has microphone permissions in System Settings (macOS: System Settings > Privacy & Security > Microphone)\\n2. You restart the app after granting permissions\\n3. You are using Tauri v2 with a webview that supports getUserMedia'\n            : 'Microphone access is not available. Please ensure you are using a secure context (HTTPS or localhost) and that your browser has microphone permissions enabled.';\n          setError(errorMsg);\n          throw new Error(errorMsg);\n        }\n      }\n\n      // Request microphone access\n      const stream = await navigator.mediaDevices.getUserMedia({\n        audio: {\n          echoCancellation: true,\n          noiseSuppression: true,\n          autoGainControl: true,\n        },\n      });\n\n      streamRef.current = stream;\n\n      // Create MediaRecorder with preferred MIME type\n      const options: MediaRecorderOptions = {\n        mimeType: 'audio/webm;codecs=opus',\n      };","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/app/src/lib/hooks/useAudioRecording.ts#L39-L75","documentation":"Thrown by `startRecording()` in `useAudioRecording.ts` (line 53-57) on the Tauri branch when `navigator.mediaDevices` or `getUserMedia` is still absent after a 100 ms wait. The message enumerates the macOS permission grant flow and the Tauri v2 requirement. `platform.metadata.isTauri` selects this branch.","triggerScenarios":"Running inside Tauri v2 but the OS has not granted microphone permission to the app; the Tauri config (capabilities/permissions) does not allow media access; the bundled webview is older than WebView2/WKWebView and lacks `getUserMedia`; permission was granted but the app was not restarted so the webview has not picked it up.","commonSituations":"First run on macOS where the mic permission prompt was dismissed/denied; `tauri.conf.json` capabilities missing the media/microphone permission; using a Tauri v1 build where `isTauri` is set but getUserMedia is unsupported; permission toggled in System Settings but the app must be restarted for the webview to see it.","solutions":["Open System Settings > Privacy & Security > Microphone and enable the app, then fully quit and restart it.","Verify `tauri.conf.json` / capabilities grant microphone access for Tauri v2 and that the app declares the usage description.","Confirm the build is Tauri v2 with a modern WKWebView (macOS)/WebView2 (Windows).","If denied permanently, reset the permission (`tccutil reset Microphone <bundle-id>` on macOS) and re-prompt."],"exampleFix":"// before — synchronous check fails immediately\nawait startRecording();\n\n// after — surface a re-prompt + retry after the user opens Settings\ntry { await startRecording(); }\ncatch (e) {\n  if (/microphone/i.test(e.message)) {\n    showSettingsOpenDialog(); // guide user to System Settings, then retry\n  }\n}","handlingStrategy":"try-catch","validationCode":"// Detect the missing API early and guide the user to grant permission\nif (platform.metadata.isTauri && !navigator.mediaDevices?.getUserMedia) {\n  throw new Error('Microphone permission needed — grant it in System Settings and restart.');\n}","typeGuard":"function hasGetUserMedia(): boolean {\n  return typeof navigator !== 'undefined'\n    && !!navigator.mediaDevices\n    && typeof navigator.mediaDevices.getUserMedia === 'function';\n}","tryCatchPattern":"try {\n  await startRecording();\n} catch (e) {\n  if (/microphone/i.test((e as Error).message)) {\n    showOpenSystemSettingsDialog(); // then offer a Retry button\n  } else throw e;\n}","preventionTips":["Declare microphone permission + usage description in the Tauri v2 capabilities config.","On first run, trigger the OS permission prompt explicitly before recording.","After the user grants permission, require an app restart and communicate that."],"tags":["microphone","permissions","tauri","getusermedia","voicebox"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}