{"record":{"id":"810517917c47a321","repo":"stablyai/orca","slug":"microphone-access-not-granted-in-system-settings","errorCode":null,"errorMessage":"Microphone access not granted. In System Settings > Privacy & Security > Microphone, click \"+\" and add the Electron app, then restart Orca.","messagePattern":"Microphone access not granted\\. In System Settings > Privacy & Security > Microphone, click \"\\+\" and add the Electron app, then restart Orca\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/speech.ts","lineNumber":128,"sourceCode":"          .catch(() => {})\n      }\n      const cleanupSessionListener = (): void => {\n        window.off('closed', cleanupOnWindowClosed)\n      }\n      window.once('closed', cleanupOnWindowClosed)\n\n      try {\n        // Why: on macOS, the Electron binary needs explicit TCC permission for\n        // the microphone. Without it, getUserMedia succeeds but returns a silent\n        // stream (all zeros). Check status and attempt to trigger the system\n        // permission prompt if not yet granted.\n        if (process.platform === 'darwin') {\n          const micStatus = systemPreferences.getMediaAccessStatus('microphone')\n          if (micStatus !== 'granted') {\n            await systemPreferences.askForMediaAccess('microphone')\n            const newStatus = systemPreferences.getMediaAccessStatus('microphone')\n            if (newStatus !== 'granted') {\n              throw new Error(\n                'Microphone access not granted. In System Settings > Privacy & Security > Microphone, ' +\n                  'click \"+\" and add the Electron app, then restart Orca.'\n              )\n            }\n          }\n        }\n\n        if (hotwords && hotwords.length > 0) {\n          const content = `${hotwords.map((w) => `${w} :2.0`).join('\\n')}\\n`\n          const hotwordsFilePath = getHotwordsFilePath(content)\n          await writeFile(hotwordsFilePath, content, 'utf-8')\n          resolvedHotwordsPath = hotwordsFilePath\n        }\n\n        if (windowClosed || window.isDestroyed()) {\n          cleanupSessionListener()\n          if (resolvedHotwordsPath) {\n            unlink(resolvedHotwordsPath).catch(() => {})","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/speech.ts#L110-L146","documentation":"Thrown during speech/microphone setup on macOS when systemPreferences.getMediaAccessStatus('microphone') does not return 'granted' even after an explicit askForMediaAccess('microphone') call. This is the Electron TCC (Transparency, Consent, and Control) layer: the OS must list the Electron binary under System Settings > Privacy & Security > Microphone, otherwise getUserMedia returns a silent zero-filled stream. The error tells the user how to grant the permission manually because the programmatic prompt can be dismissed or denied.","triggerScenarios":"process.platform === 'darwin' and the mic status is 'denied', 'restricted', or 'not-determined' both before and after systemPreferences.askForMediaAccess('microphone'). Happens on first run, after the user clicked 'Don't Allow' on a prior prompt, or after a macOS/MDM policy revoked the entitlement.","commonSituations":"First launch on a new Mac where TCC has no entry for the app. The user previously denied access and the choice is sticky. An MDM profile forces microphone privacy restrictions. The app bundle was rebuilt/re-signed so macOS treats it as a new identity and resets TCC state.","solutions":["Open System Settings > Privacy & Security > Microphone, click '+', add the Electron/Orca app, ensure its toggle is on, then restart Orca.","Reset the denied decision first: run `tccutil reset Microphone <bundle-id>` (or `tccutil reset Microphone` for all), then relaunch so the prompt re-appears.","Verify Info.plist includes NSMicrophoneUsageDescription and the entitlements/macOS hardened runtime permits the microphone; without it the prompt never shows.","If an MDM profile is enforcing the restriction, work with the device administrator to allowlist the app."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import { systemPreferences } from 'electron'\nfunction isMicGranted(): boolean {\n  return process.platform !== 'darwin' || systemPreferences.getMediaAccessStatus('microphone') === 'granted'\n}","typeGuard":null,"tryCatchPattern":"try {\n  await startSpeechRecognition({ hotwords })\n} catch (e) {\n  if (/Microphone access not granted/.test((e as Error).message)) {\n    showMacOSPermissionInstructions()\n  } else throw e\n}","preventionTips":["Include NSMicrophoneUsageDescription in Info.plist and the mic entitlement in hardened runtime.","On first launch, call askForMediaAccess('microphone') proactively before the user starts speech.","Reset a stuck 'denied' state with tccutil reset Microphone during development."],"tags":["macos","permissions","microphone","tcc","electron","speech"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}