cjpais/Handy · warning
Failed to check Windows microphone permissions:
Error message
Failed to check Windows microphone permissions:
What it means
In the Windows branch of AccessibilityOnboarding's checkInitial, the app invokes the Tauri command behind hasWindowsMicrophoneAccess() to read the OS microphone privacy setting. If the invoke rejects, this catch logs the failure and deliberately fails open: it marks microphone as granted and auto-completes onboarding. So the message never blocks the user, but it means the real permission state was never established.
Source
Thrown at src/components/onboarding/AccessibilityOnboarding.tsx:149
});
}
return;
}
try {
const microphoneGranted = await hasWindowsMicrophoneAccess();
setPermissions({
accessibility: "granted",
microphone: microphoneGranted ? "granted" : "needed",
});
if (microphoneGranted) {
await completeOnboarding();
}
} catch (error) {
console.warn("Failed to check Windows microphone permissions:", error);
setPermissions({
accessibility: "granted",
microphone: "granted",
});
await completeOnboarding();
}
};
checkInitial();
}, [completeOnboarding, hasWindowsMicrophoneAccess, onComplete, t]);
// Polling for permissions after user clicks a button
const startPolling = useCallback(() => {
if (pollingRef.current || permissionPlatform === null) return;
pollingRef.current = setInterval(async () => {
try {
if (permissionPlatform === "windows") {View on GitHub (pinned to c89b7bf389)
Solutions
- If it only appears in browser dev, guard with isTauri() from @tauri-apps/api/core before invoking
- Confirm the command appears in the tauri generate_handler! invoke_handler list for Windows builds
- Retry the check once after a short delay to rule out startup races before failing open
- Reconsider the fail-open policy: route the error to the permission step UI instead of auto-granting, so users are not silently onboarded with a broken mic
Example fix
// before
} catch (error) {
console.warn("Failed to check Windows microphone permissions:", error);
setPermissions({ accessibility: "granted", microphone: "granted" });
await completeOnboarding();
}
// after
import { isTauri } from "@tauri-apps/api/core";
// ...
} catch (error) {
if (!isTauri()) return; // browser dev: skip, do not complete onboarding
console.warn("Failed to check Windows microphone permissions:", error);
setPermissions((p) => ({ ...p, microphone: "needed" })); // fail visible, not open
} Defensive patterns
Strategy: try-catch
Validate before calling
import { isTauri } from "@tauri-apps/api/core";
if (!isTauri()) return; // browser dev: skip permission invoke entirely Try / catch
try {
const granted = await hasWindowsMicrophoneAccess();
/* handle */
} catch (error) {
console.warn("Failed to check Windows microphone permissions:", error);
// decide policy explicitly: fail-open (current) vs fail-visible
setPermissions((p) => ({ ...p, microphone: "needed" }));
} Prevention
- Gate all Tauri invokes with isTauri() when the frontend must also run in a browser
- Confirm commands are in generate_handler! before wiring a UI flow to them
- Do not auto-complete onboarding inside a catch — surface the uncertain state instead
When it happens
Trigger: The invoke rejecting because the backend is not yet ready when the component mounts; the command not being registered in a stripped/dev build; the Windows privacy registry/service read erroring; or running the frontend via plain `bun run dev` in a browser where Tauri invoke always rejects.
Common situations: Iterating UI in Vite outside the Tauri shell; racing between webview load and command handler registration; Windows builds where the privacy-settings query API returns an unexpected error.
Related errors
- Failed to check Windows microphone permissions:
- Failed to show main window for permission onboarding:
- Failed to check macOS permissions:
- Failed to initialize after permission grant:
- Failed to sync language from settings:
AI-assisted analysis of cjpais/Handy@c89b7bf389 (2026-08-17).
Data as JSON: /api/errors/939ee6dbe1a3a6d2.
Report an issue: GitHub.