{"record":{"id":"4089662ad95d138e","repo":"cjpais/Handy","slug":"failed-to-initialize-after-permission-grant","errorCode":null,"errorMessage":"Failed to initialize after permission grant:","messagePattern":"Failed to initialize after permission grant:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/components/onboarding/AccessibilityOnboarding.tsx","lineNumber":111,"sourceCode":"    }\n\n    const checkInitial = async () => {\n      if (nextPlatform === \"macos\") {\n        try {\n          const [accessibilityGranted, microphoneGranted] = await Promise.all([\n            checkAccessibilityPermission(),\n            checkMicrophonePermission(),\n          ]);\n\n          // If accessibility is granted, initialize Enigo and shortcuts\n          if (accessibilityGranted) {\n            try {\n              await Promise.all([\n                commands.initializeEnigo(),\n                commands.initializeShortcuts(),\n              ]);\n            } catch (e) {\n              console.warn(\"Failed to initialize after permission grant:\", e);\n            }\n          }\n\n          const newState: PermissionsState = {\n            accessibility: accessibilityGranted ? \"granted\" : \"needed\",\n            microphone: microphoneGranted ? \"granted\" : \"needed\",\n          };\n\n          setPermissions(newState);\n\n          if (accessibilityGranted && microphoneGranted) {\n            await completeOnboarding();\n          }\n        } catch (error) {\n          console.error(\"Failed to check macOS permissions:\", error);\n          toast.error(t(\"onboarding.permissions.errors.checkFailed\"));\n          setPermissions({\n            accessibility: \"needed\",","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/cjpais/Handy/blob/c89b7bf38974ad317177389f5bfe28236f0d64e3/src/components/onboarding/AccessibilityOnboarding.tsx#L93-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"Users granting accessibility permission and clicking through onboarding in the same second; macOS permission propagation delays; VMs; dev builds in a browser.","solutions":["Retry initialization once after a short delay — accessibility grants often need a beat before the API sees them","If retry fails, keep the onboarding step open with an error state instead of completing","Verify with the logged error which command failed; shortcuts failing alone points to a grab conflict, both failing points to permissions","Reuse a single shared init-with-retry helper here and in App.tsx so the two paths cannot diverge"],"exampleFix":"// before\ntry {\n  await Promise.all([commands.initializeEnigo(), commands.initializeShortcuts()]);\n} catch (e) {\n  console.warn(\"Failed to initialize after permission grant:\", e);\n}\n\n// after\nconst initWithRetry = async (retries = 2, delayMs = 1000) => {\n  for (let i = 0; i <= retries; i++) {\n    try {\n      await Promise.all([commands.initializeEnigo(), commands.initializeShortcuts()]);\n      return true;\n    } catch (e) {\n      if (i === retries) { console.warn(\"Failed to initialize after permission grant:\", e); return false; }\n      await new Promise((r) => setTimeout(r, delayMs));\n    }\n  }\n  return false;\n};","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await Promise.all([commands.initializeEnigo(), commands.initializeShortcuts()]);\n} catch (e) {\n  console.warn(\"Failed to initialize after permission grant:\", e);\n  await new Promise((r) => setTimeout(r, 1000)); // macOS grants propagate slowly\n  try { await Promise.all([commands.initializeEnigo(), commands.initializeShortcuts()]); }\n  catch (e2) { console.error(\"init failed after retry:\", e2); }\n}","preventionTips":["Never init Enigo/shortcuts exactly once at grant time — macOS accessibility grants need propagation time","Share one retrying init helper between App.tsx and onboarding so the paths cannot diverge","Keep onboarding open with an error state when init fails after retries instead of completing silently"],"tags":["tauri","macos","enigo","global-shortcuts","onboarding","permissions"],"backgroundTag":"global-shortcut-initialization-failed","analyzedSha":"c89b7bf38974ad317177389f5bfe28236f0d64e3","analyzedAt":"2026-08-17T10:29:55.597Z","contentChangedAt":"2026-08-17T10:29:55.597Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}