cjpais/Handy · warning

Failed to initialize after permission grant:

Error message

Failed to initialize after permission grant:

What it means

In AccessibilityOnboarding's macOS branch, once permissions report granted, the component re-runs initializeEnigo and initializeShortcuts (mirroring App.tsx's post-onboarding init). If either rejects, this catch logs and onboarding continues to completion — leaving input simulation and global shortcuts silently non-functional while the UI reports everything as set up.

Source

Thrown at src/components/onboarding/AccessibilityOnboarding.tsx:111

    }

    const checkInitial = async () => {
      if (nextPlatform === "macos") {
        try {
          const [accessibilityGranted, microphoneGranted] = await Promise.all([
            checkAccessibilityPermission(),
            checkMicrophonePermission(),
          ]);

          // If accessibility is granted, initialize Enigo and shortcuts
          if (accessibilityGranted) {
            try {
              await Promise.all([
                commands.initializeEnigo(),
                commands.initializeShortcuts(),
              ]);
            } catch (e) {
              console.warn("Failed to initialize after permission grant:", e);
            }
          }

          const newState: PermissionsState = {
            accessibility: accessibilityGranted ? "granted" : "needed",
            microphone: microphoneGranted ? "granted" : "needed",
          };

          setPermissions(newState);

          if (accessibilityGranted && microphoneGranted) {
            await completeOnboarding();
          }
        } catch (error) {
          console.error("Failed to check macOS permissions:", error);
          toast.error(t("onboarding.permissions.errors.checkFailed"));
          setPermissions({
            accessibility: "needed",

View on GitHub (pinned to c89b7bf389)

Solutions

  1. Retry initialization once after a short delay — accessibility grants often need a beat before the API sees them
  2. If retry fails, keep the onboarding step open with an error state instead of completing
  3. Verify with the logged error which command failed; shortcuts failing alone points to a grab conflict, both failing points to permissions
  4. Reuse a single shared init-with-retry helper here and in App.tsx so the two paths cannot diverge

Example fix

// before
try {
  await Promise.all([commands.initializeEnigo(), commands.initializeShortcuts()]);
} catch (e) {
  console.warn("Failed to initialize after permission grant:", e);
}

// after
const initWithRetry = async (retries = 2, delayMs = 1000) => {
  for (let i = 0; i <= retries; i++) {
    try {
      await Promise.all([commands.initializeEnigo(), commands.initializeShortcuts()]);
      return true;
    } catch (e) {
      if (i === retries) { console.warn("Failed to initialize after permission grant:", e); return false; }
      await new Promise((r) => setTimeout(r, delayMs));
    }
  }
  return false;
};
Defensive patterns

Strategy: retry

Try / catch

try {
  await Promise.all([commands.initializeEnigo(), commands.initializeShortcuts()]);
} catch (e) {
  console.warn("Failed to initialize after permission grant:", e);
  await new Promise((r) => setTimeout(r, 1000)); // macOS grants propagate slowly
  try { await Promise.all([commands.initializeEnigo(), commands.initializeShortcuts()]); }
  catch (e2) { console.error("init failed after retry:", e2); }
}

Prevention

When it happens

Trigger: Enigo init failing on a macOS system where the accessibility grant has not fully propagated yet (grant-then-immediately-init is a classic macOS race); the shortcut grab failing because another app holds it; invoking after backend teardown; non-Tauri dev context.

Common situations: Users granting accessibility permission and clicking through onboarding in the same second; macOS permission propagation delays; VMs; dev builds in a browser.

Related errors


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