{"record":{"id":"b135036688f88f92","repo":"eythaann/Seelen-UI","slug":"widget-is-already-ready","errorCode":null,"errorMessage":"Widget is already ready","messagePattern":"Widget is already ready","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"libs/core/src/state/widget/mod.ts","lineNumber":298,"sourceCode":"      console.trace(\"Animations won't be disabled because widget configuration\");\n    }\n  }\n\n  /**\n   * Will mark the widget as `ready` and pool pending triggers.\n   *\n   * If the widget is not lazy this will inmediately show the widget.\n   * Lazy widget should be shown on trigger action.\n   */\n  public async ready(options: ReadyWidgetOptions = {}): Promise<void> {\n    const { show = !this.def.lazy } = options;\n\n    if (!this.runtimeState.initialized) {\n      throw new Error(`Widget was not initialized before ready`);\n    }\n\n    if (this.runtimeState.ready) {\n      console.warn(`Widget is already ready`);\n      return;\n    }\n\n    this.runtimeState.ready = true;\n    await this.autoSizer?.execute();\n\n    if (show && !(await this.window.isVisible())) {\n      await this.show();\n    }\n\n    // this will mark the widget as ready, and send pending trigger event if exists\n    await invoke(SeelenCommand.SetCurrentWidgetStatus, { status: WidgetStatus.Ready });\n  }\n\n  public onTrigger(cb: (args: WidgetTriggerPayload) => void): void {\n    this.webview.listen<WidgetTriggerPayload>(SeelenEvent.WidgetTriggered, ({ payload }) => {\n      cb(payload);\n    });","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/eythaann/Seelen-UI/blob/dee4aaa94066c5d0888ab25554864862fc47be15/libs/core/src/state/widget/mod.ts#L280-L316","documentation":"In Seelen UI's Widget class (libs/core), ready() marks the widget as ready, runs the auto-sizer and shows the window. If ready() is called after runtimeState.ready is already true, the call is a no-op and this warning is logged instead of re-running initialization. It guards against double-invocation of a one-shot lifecycle method (a real Error is thrown only for calling ready() before init()).","triggerScenarios":"Calling widget.ready() twice on the same Widget instance — e.g. awaiting ready() in an async init path that also has a caller-side ready() call, or a React/Svelte effect re-running (StrictMode double-mount, dependency change) that re-invokes ready() on the same instance.","commonSituations":"Hot module reload or dev StrictMode re-mounts re-running the init script; widget code that calls ready() inside both a global setup hook and a component effect; frameworks re-executing entry modules without recreating the Widget.","solutions":["Call ready() exactly once per Widget instance — move it to a single entry point (e.g. after Widget.getCurrent().init(...) resolves).","Guard with a module-level promise flag: if (readinessPromise) return readinessPromise; readinessPromise = widget.ready().","In React, wrap the ready() call in an effect with an empty dependency array and proper cleanup awareness; in Svelte 5 use $effect with onCleanup or run once in module scope after init.","If intentionally re-calling, ignore the warning — the implementation safely returns early."],"exampleFix":"// before\nclass App {\n  constructor() { this.init(); }\n  async init() {\n    const widget = Widget.getCurrent();\n    await widget.init({ name: \"my-widget\" });\n    await widget.ready();\n    // later, another code path also calls:\n    await widget.ready(); // -> \"Widget is already ready\"\n  }\n}\n\n// after\nlet readiness: Promise<void> | null = null;\nasync function markReady(widget: Widget) {\n  readiness ??= widget.ready();\n  return readiness; // idempotent, no double call\n}","handlingStrategy":"validation","validationCode":"let readiness: Promise<void> | null = null;\nfunction markReadyOnce(widget: Widget): Promise<void> {\n  readiness ??= widget.ready();\n  return readiness;\n}","typeGuard":"function canCallReady(widget: Widget & { __readyCalled?: boolean }): boolean {\n  return !widget.__readyCalled;\n}","tryCatchPattern":null,"preventionTips":["Call ready() only once, in a single well-known place after init() resolves.","Memoize the ready() promise so repeated calls reuse the same promise.","Be aware of React StrictMode / HMR double-mounts when invoking ready() in effects.","Treat the warning as benign — the implementation returns early by design."],"tags":["widget","lifecycle","double-invocation","seelen-ui"],"backgroundTag":"widget-ready-already-called","analyzedSha":"dee4aaa94066c5d0888ab25554864862fc47be15","analyzedAt":"2026-09-03T10:20:37.842Z","contentChangedAt":"2026-09-03T10:20:37.842Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}