actualbudget/actual · error · Error

budget-not-found

budget-not-found

Error message

Budget "${syncId}" not found. Check the sync id of your budget in the Advanced section of the settings page.

What it means

Thrown by api/download-budget in packages/loot-core/src/server/api.ts when the remote file list was fetched successfully but no file has a groupId matching the provided syncId. Tagged with code 'budget-not-found'. The message explicitly directs the user to check the sync id in the Advanced section of the settings page.

Source

Thrown at packages/loot-core/src/server/api.ts:201

    await handlers['close-budget']();
  }

  const budgets = await handlers['get-budgets']();
  const localBudget = budgets.find(b => b.groupId === syncId);
  let remoteBudget: RemoteFile;

  // Load a remote file if we could not find the file locally
  if (!localBudget) {
    const files = await handlers['get-remote-files']();
    if (!files) {
      throw withErrorCode(
        new Error('Could not get remote files'),
        'network-failure',
      );
    }
    const file = files.find(f => f.groupId === syncId);
    if (!file) {
      throw withErrorCode(
        new Error(
          `Budget "${syncId}" not found. Check the sync id of your budget in the Advanced section of the settings page.`,
        ),
        'budget-not-found',
      );
    }

    remoteBudget = file;
  }

  const activeFile = remoteBudget ? remoteBudget : localBudget;

  // Set the e2e encryption keys
  if (activeFile.encryptKeyId) {
    if (!password) {
      throw withErrorCode(
        new Error(
          `File ${activeFile.name} is encrypted. Please provide a password.`,

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Open the server's web app > Settings > Advanced and copy the exact sync id of the budget
  2. Confirm you are connecting to the correct sync server instance
  3. List remote files programmatically (get-remote-files) and match groupId before downloading
  4. If the budget was deleted, restore from the server's data directory backup or re-upload it

Example fix

// before
await api.downloadBudget('abc123');
// after
const files = await api.getRemoteFiles?.() ?? [];
const match = files.find(f => f.groupId === syncId);
if (!match) throw new Error(`No remote budget with syncId ${syncId}; check Settings > Advanced`);
await api.downloadBudget(syncId);
Defensive patterns

Strategy: validation

Validate before calling

const remote = await getRemoteFiles();
if (!remote.some(f => f.groupId === syncId)) throw new Error(`Unknown syncId: ${syncId}`);

Type guard

function isRemoteFile(f: unknown): f is { groupId: string; fileId: string } {
  return typeof f === 'object' && f !== null && typeof (f as any).groupId === 'string';
}

Try / catch

try {
  await api.downloadBudget(syncId);
} catch (e) {
  if (e.code === 'budget-not-found') {
    const ids = (await getRemoteFiles()).map(f => f.groupId);
    throw new Error(`${syncId} not found. Known ids: ${ids.join(', ')}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling downloadBudget(syncId) where syncId does not match any remote budget's groupId — wrong id, budget deleted from the server, or the local file exists under a different sync id so the remote lookup path ran against the wrong id.

Common situations: Copy-pasting the wrong id (e.g. fileId instead of groupId/syncId); budget deleted via the settings page on another device; connecting to a different sync server than the one hosting the budget.

Related errors


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