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
- 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
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
- 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
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
- Failed to check macOS permissions:
- Failed to check Windows microphone permissions:
- Failed to initialize:
- Failed to check Windows microphone permissions:
- Failed to show main window for permission onboarding:
AI-assisted analysis of cjpais/Handy@c89b7bf389 (2026-08-17).
Data as JSON: /api/errors/4089662ad95d138e.
Report an issue: GitHub.