linshenkx/prompt-optimizer · error · FavoriteStorageError

Electron API not available. Please ensure preload script is

Error message

Electron API not available. Please ensure preload script is loaded and window.electronAPI.favoriteManager is accessible.

What it means

Thrown by FavoriteManagerElectronProxy.ensureApiAvailable when window.electronAPI.favoriteManager is not present. The proxy delegates all favorite operations to Electron via IPC, so it refuses to run outside a properly configured Electron renderer with the preload script exposed.

Source

Thrown at packages/core/src/services/favorite/electron-proxy.ts:34

import { toErrorWithCode } from '../../utils/error'
import { safeSerializeArgs } from '../../utils/ipc-serialization'

declare const window: {
  electronAPI: {
    favoriteManager: IFavoriteManager;
  }
};

/**
 * Electron 收藏服务代理
 * 在渲染进程中通过 window.electronAPI 与主进程的收藏服务通信
 */
export class FavoriteManagerElectronProxy implements IFavoriteManager {

  private ensureApiAvailable() {
    const windowAny = window as any;
    if (!windowAny?.electronAPI?.favoriteManager) {
      throw new FavoriteStorageError(
        'Electron API not available. Please ensure preload script is loaded and window.electronAPI.favoriteManager is accessible.',
      );
    }
  }

  private async invokeMethod<T>(method: string, ...args: any[]): Promise<T> {
    this.ensureApiAvailable();
    try {
      const safeArgs = safeSerializeArgs(...args);
      return await (window.electronAPI.favoriteManager as any)[method](...safeArgs);
    } catch (error: any) {
      // New i18n-style structured errors: pass through as-is so UI can translate via `code + params`.
      if (typeof error?.code === 'string' && error.code.startsWith('error.')) {
        throw toErrorWithCode(error)
      }

      // 将IPC错误转换为具体的错误类型
      if (error.code === 'FAVORITE_NOT_FOUND') {

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Verify the preload script is configured: webPreferences.preload points to the built preload bundle
  2. Confirm the preload exposes favoriteManager under electronAPI (check spelling/shape) in the version you ship
  3. If running in a browser/web build, use the web/local implementation of IFavoriteManager instead of the Electron proxy
  4. In tests, mock window.electronAPI.favoriteManager before constructing the proxy

Example fix

// before
const mgr = new FavoriteManagerElectronProxy();
// after (browser/tests)
(window as any).electronAPI = { favoriteManager: fakeApi };
const mgr = new FavoriteManagerElectronProxy();
Defensive patterns

Strategy: type-guard

Validate before calling

const hasElectronApi = () =>
  typeof window !== 'undefined' && !!(window as any).electronAPI?.favoriteManager;

Type guard

const hasFavoriteElectronApi = (w: Window): w is Window & { electronAPI: { favoriteManager: object } } =>
  !!(w as any).electronAPI?.favoriteManager;

Try / catch

if (!hasElectronApi()) { useWebFavoriteManager(); } else { useElectronProxy(); }

Prevention

When it happens

Trigger: Instantiating/using FavoriteManagerElectronProxy in a plain browser tab, in tests/jsdom without mocking window.electronAPI, or in an Electron app where contextIsolation is on but the preload script does not expose favoriteManager on electronAPI.

Common situations: Running the app in a browser instead of Electron; preload script not listed in BrowserWindow webPreferences; contextIsolation/sandbox flags changed; preload bundle failed to load silently; version mismatch between core package and preload API surface.

Related errors


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/38baaa63aca74e9b. Report an issue: GitHub.