actualbudget/actual · error · Error

load-key-error

load-key-error

Error message

load-key-error

What it means

During initApp, Actual loads per-file encryption keys from the sync server via encryption.loadKey. If any key fails to load or decrypt (wrong password, corrupt key blob, key missing), the error is logged and this coded error is thrown so the client can map it to a user-facing message.

Source

Thrown at packages/loot-core/src/server/main.ts:208

  await sqlite.init();
  asyncStorage.init();
  await fs.init();
  await setupDocumentsDir();

  const keysStr = await asyncStorage.getItem('encrypt-keys');
  if (keysStr) {
    try {
      const keys = JSON.parse(keysStr);

      // Load all the keys
      await Promise.all(
        Object.keys(keys).map(fileId => {
          return encryption.loadKey(keys[fileId]);
        }),
      );
    } catch (e) {
      logger.log('Error loading key', e);
      throw new Error('load-key-error');
    }
  }

  const url = await asyncStorage.getItem('server-url');

  if (!url) {
    await asyncStorage.removeItem('user-token');
  }
  setServer(url);

  connection.init(socketName, app.handlers);

  // Allow running DB queries locally
  global.$query = aqlQuery;
  global.$q = q;

  if (isDev) {
    global.$send = (name, args) => runHandler(app.handlers[name], args);

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Enter the correct encryption password for the budget when prompted (the key was encrypted with the original password).
  2. If the password was changed, re-set it from the client that can still open the budget so the server key matches.
  3. Check the server logs for the logged 'Error loading key' detail to distinguish corrupt key data from a wrong password.
  4. If the key is unrecoverable, restore the affected files/key store from a server backup, or reset end-to-end encryption (accepting that old encrypted data may be lost).
Defensive patterns

Strategy: try-catch

Validate before calling

// before opening a budget, confirm the server is reachable and key exists
const res = await fetch(`${serverUrl}/status`);
if (!res.ok) throw new Error('sync server unreachable');

Try / catch

try {
  await initApp();
} catch (e) {
  if (e.message === 'load-key-error') {
    // prompt user for the budget's encryption password or check server key files
  } else throw e;
}

Prevention

When it happens

Trigger: Opening a budget whose encryption key file on the server cannot be decrypted — e.g. the user changed or forgot the budget's end-to-end encryption password, or the key record is missing/corrupt in the server's key store.

Common situations: Changing the encryption password in one client while another client still caches the old one; restoring a server from backup without the key files; server data dir partially deleted; decrypting with a different password than the one used to encrypt.

Related errors


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