{"record":{"id":"de2eed336789b2eb","repo":"cjpais/Handy","slug":"failed-to-fetch-secure-input-status","errorCode":null,"errorMessage":"Failed to fetch secure input status:","messagePattern":"Failed to fetch secure input status:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/components/SecureInputWarning.tsx","lineNumber":30,"sourceCode":"/**\n * Compact warning banner shown while macOS Secure Input is stuck on.\n *\n * Secure Input (password fields, Terminal's \"Secure Keyboard Entry\", a stuck\n * loginwindow) blocks key events from reaching Handy's keyboard listener, so\n * keyed shortcuts silently stop firing (issue #1578). The backend monitor\n * emits `secure-input-changed` on state transitions; `sustained` filters out\n * the normal momentary activation from focusing a password field.\n */\nconst SecureInputWarning: React.FC = () => {\n  const { t } = useTranslation();\n  const [status, setStatus] = useState<SecureInputStatus | null>(null);\n  const [dismissed, setDismissed] = useState(false);\n\n  const refresh = useCallback(async () => {\n    try {\n      setStatus(await commands.getSecureInputStatus());\n    } catch (e) {\n      console.warn(\"Failed to fetch secure input status:\", e);\n    }\n  }, []);\n\n  useEffect(() => {\n    refresh();\n    const unlisten = listen<SecureInputStatus>(\n      \"secure-input-changed\",\n      (event) => setStatus(event.payload),\n    );\n    return () => {\n      unlisten.then((fn) => fn());\n    };\n  }, [refresh]);\n\n  // Only warn when the user is actually impacted: a binding is degraded\n  // (side-specific matching widened) or dead (e.g. fn+key), or they ran into\n  // the blocked shortcut recorder. When the fallback covers everything\n  // transparently — and nothing else surfaced — stay silent; the backend","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/cjpais/Handy/blob/c89b7bf38974ad317177389f5bfe28236f0d64e3/src/components/SecureInputWarning.tsx#L12-L48","documentation":"SecureInputWarning mounts and immediately fetches macOS Secure Input state via the getSecureInputStatus command, then subscribes to the secure-input-changed event. If the initial fetch rejects, this catch logs it; status stays null so the warning banner stays hidden until a subsequent event arrives. Because the component also listens for changes, the practical impact is limited to missing a pre-existing secure-input state at mount.","triggerScenarios":"The invoke firing before the backend command/watcher is ready; the command erroring on non-macOS platforms if the component is mounted there; the secure-input watcher thread failing to spawn in the Rust backend; browser dev where invoke rejects.","commonSituations":"Mount-time races at app startup; development outside Tauri; macOS keychain/SecureInput API edge cases where the poll errors.","solutions":["Re-run refresh() after the unlisten promise resolves (subscription confirmed) or on window focus to cover mount races","Skip mounting the component on non-macOS platforms (it is a macOS-only concern)","Guard with isTauri() for browser development","Have the Rust command log its own failure cause so the warn payload identifies the real error"],"exampleFix":"// before\nuseEffect(() => {\n  refresh();\n  const unlisten = listen<SecureInputStatus>(\"secure-input-changed\", (event) => setStatus(event.payload));\n  return () => { unlisten.then((fn) => fn()); };\n}, []);\n\n// after\nuseEffect(() => {\n  refresh();\n  const unlisten = listen<SecureInputStatus>(\"secure-input-changed\", (event) => setStatus(event.payload));\n  unlisten.then(() => refresh()); // re-poll once the subscription is live\n  return () => { unlisten.then((fn) => fn()); };\n}, [refresh]);","handlingStrategy":"retry","validationCode":"// Only mount on macOS, inside Tauri\n{platform() === \"macos\" && isTauri() && <SecureInputWarning />}","typeGuard":null,"tryCatchPattern":"const refresh = useCallback(async () => {\n  try { setStatus(await commands.getSecureInputStatus()); }\n  catch (e) { console.warn(\"Failed to fetch secure input status:\", e); }\n}, []);","preventionTips":["Re-poll after the event subscription is confirmed live to cover mount races","Log the backend error detail so non-macOS or watcher-spawn failures are identifiable","Treat a null status as 'unknown', not 'inactive', in render logic"],"tags":["tauri","macos","secure-input","react","invoke"],"backgroundTag":"secure-input-status-check-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"}