eythaann/Seelen-UI · warning

Widget is already ready

Error message

Widget is already ready

What it means

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()).

Source

Thrown at libs/core/src/state/widget/mod.ts:298

      console.trace("Animations won't be disabled because widget configuration");
    }
  }

  /**
   * Will mark the widget as `ready` and pool pending triggers.
   *
   * If the widget is not lazy this will inmediately show the widget.
   * Lazy widget should be shown on trigger action.
   */
  public async ready(options: ReadyWidgetOptions = {}): Promise<void> {
    const { show = !this.def.lazy } = options;

    if (!this.runtimeState.initialized) {
      throw new Error(`Widget was not initialized before ready`);
    }

    if (this.runtimeState.ready) {
      console.warn(`Widget is already ready`);
      return;
    }

    this.runtimeState.ready = true;
    await this.autoSizer?.execute();

    if (show && !(await this.window.isVisible())) {
      await this.show();
    }

    // this will mark the widget as ready, and send pending trigger event if exists
    await invoke(SeelenCommand.SetCurrentWidgetStatus, { status: WidgetStatus.Ready });
  }

  public onTrigger(cb: (args: WidgetTriggerPayload) => void): void {
    this.webview.listen<WidgetTriggerPayload>(SeelenEvent.WidgetTriggered, ({ payload }) => {
      cb(payload);
    });

View on GitHub (pinned to dee4aaa940)

Solutions

  1. Call ready() exactly once per Widget instance — move it to a single entry point (e.g. after Widget.getCurrent().init(...) resolves).
  2. Guard with a module-level promise flag: if (readinessPromise) return readinessPromise; readinessPromise = widget.ready().
  3. 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.
  4. If intentionally re-calling, ignore the warning — the implementation safely returns early.

Example fix

// before
class App {
  constructor() { this.init(); }
  async init() {
    const widget = Widget.getCurrent();
    await widget.init({ name: "my-widget" });
    await widget.ready();
    // later, another code path also calls:
    await widget.ready(); // -> "Widget is already ready"
  }
}

// after
let readiness: Promise<void> | null = null;
async function markReady(widget: Widget) {
  readiness ??= widget.ready();
  return readiness; // idempotent, no double call
}
Defensive patterns

Strategy: validation

Validate before calling

let readiness: Promise<void> | null = null;
function markReadyOnce(widget: Widget): Promise<void> {
  readiness ??= widget.ready();
  return readiness;
}

Type guard

function canCallReady(widget: Widget & { __readyCalled?: boolean }): boolean {
  return !widget.__readyCalled;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of eythaann/Seelen-UI@dee4aaa940 (2026-09-03). Data as JSON: /api/errors/b135036688f88f92. Report an issue: GitHub.