koala73/worldmonitor · error · Error

Search modal is not initialised

Error message

Search modal is not initialised

What it means

App's search-open path reads this.state.searchModal; if it is still null (search modal never initialized during boot, or torn down), it throws 'Search modal is not initialised'. This is an internal lifecycle guard ensuring modal.open() is only called on a live modal instance.

Source

Thrown at src/App.ts:1816

      }

      const togglingBeforeLoad = Boolean(options.toggle) && !this.searchManager;
      if (togglingBeforeLoad) {
        this.searchToggleDesiredOpen = !this.searchToggleDesiredOpen;
      }

      epoch = ++this.openSearchEpoch;
      const manager = await raceWebMcpAbort(this.ensureSearchManager(), options.signal);
      throwIfWebMcpAborted(options.signal);
      if (this.openSearchEpoch !== epoch) return false;
      if (pendingGate && !pendingGate.isCurrent()) return false;

      const wantOpen = togglingBeforeLoad ? this.searchToggleDesiredOpen : true;
      if (!wantOpen) return false;

      manager.updateSearchIndex();
      const modal = this.state.searchModal;
      if (!modal) throw new Error('Search modal is not initialised');
      throwIfWebMcpAborted(options.signal);
      modal.open(pendingGate ? pendingId : options.replaceOverlayId);
      if (options.initialQuery) modal.applyQuery(options.initialQuery);
      return modal.isOpen();
    } catch (error) {
      const actionWasCancelled = pendingGate !== null && !pendingGate.isCurrent();
      const invocationWasCancelled = options.signal?.aborted === true;
      if (!this.state.isDestroyed && !actionWasCancelled && !invocationWasCancelled) {
        console.warn('[search] Failed to load search manager:', error);
        if (!options.throwOnFailure) showToast('Search failed to load. Please try again.');
      }
      pendingGate?.cancel();
      if (options.throwOnFailure || options.signal?.aborted) throw error;
      return false;
    } finally {
      // Reset the toggle accumulator once the latest press settles.
      if (this.openSearchEpoch === epoch) this.searchToggleDesiredOpen = false;
    }

View on GitHub (pinned to 9361220cc0)

Solutions

  1. Wait for app boot/init completion before invoking search programmatically
  2. Check app state for searchModal availability before opening
  3. Ensure the search modal initializer runs before registering the search hotkey
  4. If caused by a teardown race, guard re-open calls against the destroyed modal instance

Example fix

// before
app.openSearch({ initialQuery: q }); // throws if modal not ready
// after
if (!app.isSearchModalInitialized()) return;
app.openSearch({ initialQuery: q });
Defensive patterns

Strategy: try-catch

Validate before calling

if (!app || typeof app.isSearchModalInitialized !== 'function' || !app.isSearchModalInitialized()) {
  return; // defer search until boot completes
}

Type guard

function canOpenSearch(app) {
  return app != null && app.state?.searchModal != null;
}

Try / catch

try {
  app.openSearch({ initialQuery: q });
} catch (e) {
  if (e.message === 'Search modal is not initialised') {
    // queue the search until app:ready, or retry after init
  } else throw e;
}

Prevention

When it happens

Trigger: Triggering search (keyboard shortcut or programmatic openSearch) before the app finishes initializing the search modal, or after the modal was destroyed; toggling search during boot or teardown races.

Common situations: User hits the search hotkey very early during page load; automated tests/e2e driving search before init completes; rapid destroy/re-init cycles (e.g. view switches) leaving state.searchModal null.

Related errors


AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01). Data as JSON: /api/errors/c0773dda54b53efd. Report an issue: GitHub.