{"record":{"id":"e7594460a3a149a3","repo":"jamiepine/voicebox","slug":"microphone-access-is-not-available-please-ensure-e75944","errorCode":null,"errorMessage":"Microphone access is not available. Please ensure you are using a secure context (HTTPS or localhost) and that your browser has microphone permissions enabled.","messagePattern":"Microphone access is not available\\. Please ensure you are using a secure context \\(HTTPS or localhost\\) and that your browser has microphone permissions enabled\\.","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 non-Tauri (browser) branch when `navigator.mediaDevices.getUserMedia` is unavailable. The message points at the secure-context requirement (HTTPS or localhost) and browser mic permissions. Selected when `platform.metadata.isTauri` is false.","triggerScenarios":"Page served over plain HTTP on a non-localhost host (getUserMedia is gated to secure contexts); browser has mic blocked site-wide; the device has no microphone; an old browser without `mediaDevices.getUserMedia`; permission revoked in site settings.","commonSituations":"Dev preview served over LAN IP on http:// (not https, not localhost) so the secure-context check fails; user previously blocked the mic on the site; corporate machine with no mic device; very old browser build.","solutions":["Serve the app over HTTPS, or access it via `http://localhost` / `http://127.0.0.1` so the context is secure.","Have the user re-prompt: click the address-bar mic icon and re-allow, or clear the site's permission and reload.","Check `navigator.mediaDevices` existence and `window.isSecureContext` before calling, and degrade gracefully.","Confirm a microphone device is present and enabled in OS settings."],"exampleFix":"// before\nawait startRecording();\n\n// after — verify secure context + capability first\nif (!window.isSecureContext) {\n  throw new Error('Microphone needs HTTPS or localhost (secure context).');\n}\nif (!navigator.mediaDevices?.getUserMedia) {\n  throw new Error('This browser does not support getUserMedia.');\n}\nawait startRecording();","handlingStrategy":"validation","validationCode":"if (!window.isSecureContext) {\n  throw new Error('Microphone needs HTTPS or localhost (secure context).');\n}\nif (!navigator.mediaDevices?.getUserMedia) {\n  throw new Error('This browser does not support getUserMedia.');\n}","typeGuard":"function canRecordInBrowser(): boolean {\n  return typeof window !== 'undefined'\n    && window.isSecureContext\n    && !!navigator.mediaDevices\n    && typeof navigator.mediaDevices.getUserMedia === 'function';\n}","tryCatchPattern":"try {\n  await startRecording();\n} catch (e) {\n  if (!window.isSecureContext) toast.error('Serve over HTTPS or use localhost.');\n  else if (/permission/i.test((e as Error).message)) promptReAllowMic();\n  else throw e;\n}","preventionTips":["Serve the app over HTTPS or via http://localhost so the context is secure.","Check `window.isSecureContext` and `navigator.mediaDevices` before showing the Record button.","Guide users to re-allow the mic via the address-bar icon if previously blocked."],"tags":["microphone","permissions","browser","secure-context","getusermedia"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}