cjpais/Handy · warning

Failed to check macOS permissions:

Error message

Failed to check macOS permissions:

What it means

During startup onboarding checks, App.tsx calls the macOS-specific commands checkAccessibilityPermission and checkMicrophonePermission. If either invoke rejects, this catch logs the failure and deliberately continues into the main app so the user can fix permissions later from settings — a fail-open policy that trades strictness for not bricking first run.

Source

Thrown at src/App.tsx:208

      const currentPlatform = platform();

      if (hasCompletedOnboarding) {
        // Returning user - check if they need to grant permissions first
        setIsReturningUser(true);

        if (currentPlatform === "macos") {
          try {
            const [hasAccessibility, hasMicrophone] = await Promise.all([
              checkAccessibilityPermission(),
              checkMicrophonePermission(),
            ]);
            if (!hasAccessibility || !hasMicrophone) {
              await revealMainWindowForPermissions();
              setOnboardingStep("accessibility");
              return;
            }
          } catch (e) {
            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);

View on GitHub (pinned to c89b7bf389)

Solutions

  1. Verify the two commands are compiled and registered for macOS builds and listed in invoke_handler
  2. Guard the block with isTauri() so browser dev does not trigger it
  3. Re-check permissions once the app emits ready / the window gains focus, instead of a single mount-time call
  4. If failing open is unacceptable for your fork, route to setOnboardingStep('accessibility') on error instead of proceeding

Example fix

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

// after
import { isTauri } from "@tauri-apps/api/core";
// ...
} catch (e) {
  console.warn("Failed to check macOS permissions:", e);
  if (isTauri()) {
    await revealMainWindowForPermissions();
    setOnboardingStep("accessibility"); // fail toward the permission UI, not silently open
    return;
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

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

Try / catch

try {
  const [a, m] = await Promise.all([checkAccessibilityPermission(), checkMicrophonePermission()]);
  /* route on results */
} catch (e) {
  console.warn("Failed to check macOS permissions:", e);
  // choose fail-open (current) or fail-to-permission-UI deliberately
  await revealMainWindowForPermissions();
  setOnboardingStep("accessibility");
}

Prevention

When it happens

Trigger: The invoke rejecting when the backend is not yet ready at component mount; the commands not being registered (e.g. a non-macOS feature build that still passes the platform() check); an underlying macOS API error from the permission query; running the webview in a plain browser during development.

Common situations: Frontend development in Vite without Tauri; early-startup races; development builds where plugin-os reports 'macos' but the permission commands are cfg-gated out.

Related errors


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