eythaann/Seelen-UI · warning

Widget already initialized

Error message

Widget already initialized

What it means

`Widget.init()` guards against double initialization: if `runtimeState.initialized` is already true it logs `Widget already initialized` (console.warn, not a throw) and returns early. The library expects `init()` to be called exactly once, before any other widget action, followed by `ready()`.

Source

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

    let oldDPR = globalThis.devicePixelRatio;
    await this.webview.setZoom(1 / oldDPR);
    this.window.onScaleChanged(() => {
      if (globalThis.devicePixelRatio !== 1) {
        // when zoom was set dpr changed, so in case of change this is accomulative unit
        oldDPR = oldDPR * globalThis.devicePixelRatio;
        this.webview.setZoom(1 / oldDPR);
      }
    });
  }

  /**
   * Will initialize the widget based on the preset and mark it as `pending`, this function won't show the widget.
   * This should be called before any other action on the widget. After this you should call
   * `ready` to mark the widget as ready and show it.
   */
  public async init(options: InitWidgetOptions = {}): Promise<void> {
    if (this.runtimeState.initialized) {
      console.warn(`Widget already initialized`);
      return;
    }

    this.runtimeState.initialized = true;
    this.runtimeState.hwnd = await invoke(SeelenCommand.GetSelfWindowId);
    this.destroyOnHide = options.closeOnHide ?? this.def.lazy;

    if (options.normalizeDevicePixelRatio) {
      await this.normalizeDevicePixelRatio();
    }

    await initMonitorsState();
    await OPTIMISTIC_FRAME.runExclusive(async (state) => {
      await state.init(this);
    });

    if (options.autoSizeByContent) {
      this.autoSizer = new WidgetAutoSizer(

View on GitHub (pinned to dee4aaa940)

Solutions

  1. Call `init()` exactly once at the widget entry point; remove duplicate init calls.
  2. If re-initialization is intentional (e.g. HMR), create a new widget instance or reset `runtimeState` instead of reusing the initialized one.
  3. Treat the warning as benign if the early-return behavior is desired; check whether the second init's options (e.g. `closeOnHide`) were meant to apply and hoist them into the single init call.

Example fix

// before
const w1 = Widget.getCurrent(); await w1.init();
const w2 = Widget.getCurrent(); await w2.init(); // warns
// after
const widget = Widget.getCurrent();
await widget.init({ closeOnHide: true }); // single call
Defensive patterns

Strategy: try-catch

Validate before calling

const widget = Widget.getCurrent();
// track your own init flag if lifecycle is spread across modules
if (!widget.__myInitDone) {
  await widget.init(options);
  widget.__myInitDone = true;
}

Type guard

function needsInit(widget: Widget): boolean {
  // expose runtimeState.initialized or track it app-side
  return !(widget as any).runtimeState?.initialized;
}

Try / catch

try {
  await widget.init(options);
} catch (e) {
  if (String(e).includes("already initialized")) {
    // idempotent path: proceed with ready()
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `Widget.getCurrent().init(...)` twice — e.g. init logic in a module that is evaluated twice (HMR re-import, duplicated entry script), or calling both an app-level bootstrap and a component-level init on the same widget instance.

Common situations: Vite HMR re-running the entry module during development; mounting the widget in two places; a migration where old bootstrap code still calls `init` alongside the new `Widget.getCurrent().init`.

Related errors


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