actualbudget/actual · error · Error

applyAppUpdate not implemented in electron app

Error message

applyAppUpdate not implemented in electron app

What it means

The Electron preload bridge deliberately throws for `reload` and `applyAppUpdate` instead of providing implementations. `applyAppUpdate` exists on the browser `window.Actual` API to apply a pending service-worker update; the Electron desktop app updates itself through its own updater, so this stub signals that the browser-only method was called in the wrong environment.

Source

Thrown at packages/desktop-electron/preload.ts:109

  },

  moveBudgetDirectory: (
    currentBudgetDirectory: string,
    newDirectory: string,
  ) => {
    return ipcRenderer.invoke(
      'move-budget-directory',
      currentBudgetDirectory,
      newDirectory,
    );
  },

  reload: async () => {
    throw new Error('Reload not implemented in electron app');
  },

  applyAppUpdate: async () => {
    throw new Error('applyAppUpdate not implemented in electron app');
  },
} satisfies typeof global.Actual);

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Skip the update-apply UI flow when running under Electron (check for Electron environment before offering 'apply update')
  2. In Electron, let the app auto-update via the Electron updater path instead of calling applyAppUpdate
  3. If you truly need a no-op, wrap the call in try/catch and treat the throw as 'handled natively by desktop'

Example fix

// before
await window.Actual.applyAppUpdate();
// after
if (process.env.IS_ELECTRON) {
  // Electron applies updates itself; nothing to do
} else {
  await window.Actual.applyAppUpdate();
}
Defensive patterns

Strategy: try-catch

Validate before calling

const isElectron = typeof process !== 'undefined' && process.env.IS_ELECTRON;
if (isElectron) throw new Error('applyAppUpdate unsupported in Electron');

Type guard

const supportsApplyUpdate = (a: unknown): a is { applyAppUpdate: () => Promise<void> } =>
  typeof a === 'object' && a !== null && 'applyAppUpdate' in a;

Try / catch

try {
  await window.Actual.applyAppUpdate();
} catch (e) {
  if (String(e).includes('applyAppUpdate not implemented')) {
    // Electron handles updates natively; ignore
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `window.Actual.applyAppUpdate()` (or code in desktop-client that invokes it, e.g. the 'update available' toast flow) while running in the Electron app, because the code assumed the browser `global.Actual` API surface.

Common situations: Shared client code written for the web build being reused in the desktop build; a release-flow UI component rendering in Electron; a plugin or custom patch calling the API without checking the platform.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/8027e86c4797ee26. Report an issue: GitHub.