cjpais/Handy · warning

Failed to check Windows microphone permissions:

Error message

Failed to check Windows microphone permissions:

What it means

The Windows analog of the macOS check: App.tsx invokes getWindowsMicrophonePermissionStatus and, when supported and overall_access === "denied", routes to permission onboarding. A rejection here is logged and the flow proceeds to the main app, so the practical effect is that a mic-denied state goes undetected at startup and only surfaces later as failed recordings.

Source

Thrown at src/App.tsx:226

            console.warn("Failed to check macOS permissions:", e);
            // If we can't check, proceed to main app and let them fix it there
          }
        }

        if (currentPlatform === "windows") {
          try {
            const microphoneStatus =
              await commands.getWindowsMicrophonePermissionStatus();
            if (
              microphoneStatus.supported &&
              microphoneStatus.overall_access === "denied"
            ) {
              await revealMainWindowForPermissions();
              setOnboardingStep("accessibility");
              return;
            }
          } catch (e) {
            console.warn("Failed to check Windows microphone permissions:", e);
            // If we can't check, proceed to main app and let them fix it there
          }
        }

        setOnboardingStep("done");
      } else {
        // New user - start full onboarding
        setIsReturningUser(false);
        setOnboardingStep("accessibility");
      }
    } catch (error) {
      console.error("Failed to check onboarding status:", error);
      setOnboardingStep("accessibility");
    }
  };

  const handleAccessibilityComplete = () => {
    // Returning users already have models, skip to main app

View on GitHub (pinned to c89b7bf389)

Solutions

  1. Confirm getWindowsMicrophonePermissionStatus is in the invoke_handler list and its capability is granted
  2. Retry the check once after a short delay or on window focus to eliminate startup races
  3. Guard with isTauri() during pure-frontend development
  4. Surface a non-blocking UI hint when the check errors, so a genuinely denied mic is not silently treated as fine

Example fix

// before
} catch (e) {
  console.warn("Failed to check Windows microphone permissions:", e);
  // If we can't check, proceed to main app and let them fix it there
}

// after
} catch (e) {
  console.warn("Failed to check Windows microphone permissions:", e);
  // one delayed retry, then proceed but flag for later re-check
  setTimeout(() => void recheckWindowsMicPermission(), 2000);
}
Defensive patterns

Strategy: try-catch

Validate before calling

import { isTauri } from "@tauri-apps/api/core";
if (!isTauri()) return;

Try / catch

try {
  const st = await commands.getWindowsMicrophonePermissionStatus();
  if (st.supported && st.overall_access === "denied") { /* route to onboarding */ }
} catch (e) {
  console.warn("Failed to check Windows microphone permissions:", e);
  setTimeout(() => void recheck(), 2000); // one delayed retry, then proceed visibly
}

Prevention

When it happens

Trigger: The invoke rejecting due to a not-yet-ready backend at mount time; the command unregistered in the running build; the Windows privacy query erroring (e.g. registry access blocked by policy); browser-context development where invoke rejects unconditionally.

Common situations: Enterprise Windows with locked-down privacy settings APIs; dev iteration in a browser; capability/permission misconfigurations after Tauri upgrades; slow machines where the webview mounts before handlers register.

Related errors


AI-assisted analysis of cjpais/Handy@c89b7bf389 (2026-08-17). Data as JSON: /api/errors/7ebb99361553d316. Report an issue: GitHub.