stablyai/orca · error
Microphone permission denied
Error message
Microphone permission denied
What it means
Thrown by the start callback in use-mobile-dictation after requestMicrophonePermissionsAsync() returned a result with permission.granted === false. This is the user-level permission gate — the OS-level mic permission was denied (or restricted), so the hook refuses to proceed to initialize()/start.
Source
Thrown at mobile/src/hooks/use-mobile-dictation.ts:132
const client = clientRef.current
if (!client || !enabledRef.current || activeIdRef.current) {
return
}
const generation = generationRef.current + 1
generationRef.current = generation
setError(null)
setStatus('starting')
const permission = await requestMicrophonePermissionsAsync()
if (generationRef.current !== generation || !enabledRef.current) {
if (generationRef.current === generation) {
setStatus('idle')
}
return
}
if (!permission.granted) {
setStatus('idle')
throw new Error('Microphone permission denied')
}
const initialized = await initialize()
if (generationRef.current !== generation || !enabledRef.current) {
void tearDown()
if (generationRef.current === generation) {
setStatus('idle')
}
return
}
if (!initialized) {
setStatus('idle')
throw new Error('Failed to initialize microphone')
}
const dictationId = createMobileDictationId()
activeIdRef.current = dictationId
View on GitHub (pinned to 1136503c6a)
Solutions
- Surface a deep-link to the OS settings page so the user can re-enable the microphone permission (iOS: app settings, Android: package settings).
- Distinguish 'denied' from 'blocked'/restricted and tailor the copy — a restricted state needs an admin/MDM fix, not a settings toggle.
- Re-request only when the user explicitly taps a 'request again' affordance; do not loop requestMicrophonePermissionsAsync on mount.
- After the user returns from settings, re-run start() — the permission will now report granted.
Example fix
// before
const permission = await requestMicrophonePermissionsAsync()
if (!permission.granted) {
setStatus('idle')
throw new Error('Microphone permission denied')
}
// after — branch on the denial reason so the UI can deep-link settings
const permission = await requestMicrophonePermissionsAsync()
if (!permission.granted) {
setStatus('idle')
const reason = permission.canRequestAgain === false ? 'blocked' : 'denied'
throw new Error(`Microphone permission ${reason}`)
} Defensive patterns
Strategy: validation
Validate before calling
// Check current permission status without prompting first
const status = await getMicrophonePermissionStatusAsync()
if (status !== 'granted') {
openAppSettings()
return
} Type guard
function isMicrophonePermissionError(err: unknown): boolean {
return err instanceof Error && err.message === 'Microphone permission denied'
} Try / catch
try {
await start()
} catch (err) {
if (isMicrophonePermissionError(err)) {
showPermissionDeniedUI({ onOpenSettings: openAppSettings })
return
}
throw err
} Prevention
- Do not auto-prompt on mount; prompt only when the user taps the mic affordance.
- Deep-link to OS settings when canRequestAgain is false (previously denied).
- Distinguish 'denied' from 'blocked'/restricted so MDM-restricted users get the right guidance.
When it happens
Trigger: await requestMicrophonePermissionsAsync() resolves with {granted:false}. Reached only after the generation/enabled staleness check passes. Causes: user tapped 'Don't Allow' on the OS permission prompt, permission is restricted by MDM/screen-time policy, the prompt was previously denied and iOS now returns .denied without a prompt.
Common situations: First-time user denied the prompt; user previously denied and is retrying (iOS now needs Settings toggle); enterprise MDM blocks mic; Android permission was revoked in system settings while the app was backgrounded.
Related errors
- Failed to start microphone recording
- Microphone access not granted. In System Settings > Privacy
- Update the paired desktop Orca app to use mobile voice setti
- Failed to load dictation models
- Failed to start download
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/8e41b6a451573e8d.
Report an issue: GitHub.