{"record":{"id":"99f0430b908bec0a","repo":"jlcodes99/cockpit-tools","slug":"account-sync-failed-to-emit-eventname","errorCode":null,"errorMessage":"[account-sync] Failed to emit ${eventName}:","messagePattern":"\\[account-sync\\] Failed to emit (.+?):","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/utils/accountSyncEvents.ts","lineNumber":72,"sourceCode":"  return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, '_');\n}\n\nfunction resolveSourceWindowLabel(): string | undefined {\n  try {\n    return getCurrentWindow().label;\n  } catch {\n    return undefined;\n  }\n}\n\nasync function emitAccountSyncEvent(eventName: string, payload: AccountSyncEventPayload) {\n  try {\n    await emit<AccountSyncEventPayload>(eventName, {\n      ...payload,\n      sourceWindowLabel: payload.sourceWindowLabel ?? resolveSourceWindowLabel(),\n    });\n  } catch (error) {\n    console.warn(`[account-sync] Failed to emit ${eventName}:`, error);\n  }\n}\n\nexport function normalizeProviderPagePlatformId(platformKey: string): PlatformId | null {\n  const normalized = normalizePlatformKey(platformKey);\n  return (\n    PROVIDER_PAGE_PLATFORM_MAP[normalized] ??\n    PROVIDER_PAGE_PLATFORM_MAP[normalized.replace(/_/g, '')] ??\n    null\n  );\n}\n\nexport async function emitAccountsChanged(payload: AccountSyncEventPayload) {\n  await emitAccountSyncEvent(ACCOUNTS_CHANGED_EVENT, payload);\n}\n\nexport async function emitCurrentAccountChanged(payload: AccountSyncEventPayload) {\n  await emitAccountSyncEvent(CURRENT_ACCOUNT_CHANGED_EVENT, payload);","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/utils/accountSyncEvents.ts#L54-L90","documentation":"emitAccountSyncEvent wraps a Tauri event `emit` call in try/catch; if the cross-window event emission rejects, the failure is logged with this warning instead of propagating. This means other windows did NOT receive the account sync event, so account state can silently diverge between windows. The error is swallowed deliberately because sync events are best-effort.","triggerScenarios":"await emit<AccountSyncEventPayload>(eventName, ...) rejects — typically when the Tauri IPC/event bridge is unavailable (webview not ready, app shutting down, window closed mid-emit) or the payload fails serialization (non-JSON-safe values like undefined fields that break structured clone, functions, or circular refs).","commonSituations":"Firing account-sync events during app startup/teardown races; emitting from a secondary window that just closed; payload accidentally containing class instances or circular references after refactors.","solutions":["Read the logged `error` to see if it is a serialization error; make the payload JSON-safe (plain objects, strings, numbers only)","Check window/app lifecycle: delay emits until the Tauri runtime is ready (e.g. after 'tauri://created') and guard emits after unmount","Confirm sourceWindowLabel resolution (resolveSourceWindowLabel) isn't throwing upstream and the event name matches a registered listener","Add a reconciliation mechanism (re-read accounts on window focus) so a missed event doesn't leave stale state"],"exampleFix":"// before\nawait emit(eventName, { ...payload, updatedAt: new Date() });\n// after\nawait emit(eventName, { ...payload, updatedAt: new Date().toISOString() });","handlingStrategy":"try-catch","validationCode":"function isEmitPayloadSafe(payload: unknown): boolean {\n  try {\n    structuredClone(payload);\n    return true;\n  } catch {\n    return false;\n  }\n}","typeGuard":"function isPlainObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v) && Object.getPrototypeOf(v) === Object.prototype;\n}","tryCatchPattern":"try {\n  await emit(eventName, payload);\n} catch (error) {\n  console.warn(`[account-sync] Failed to emit ${eventName}:`, error);\n  queueMicrotask(() => broadcastStateSnapshot()); // reconcile on next tick\n}","preventionTips":["Keep event payloads plain JSON-serializable (no Dates, class instances, circular refs)","Don't emit before the Tauri runtime signals readiness or after unmount","Add a window-focus re-sync so dropped events self-heal","Log eventName with the error for faster diagnosis"],"tags":["tauri","event-emit","ipc"],"backgroundTag":"tauri-event-emit-failed","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}