actualbudget/actual · error · Error

network-failure

network-failure

Error message

Could not get remote files

What it means

Thrown by api/download-budget in packages/loot-core/src/server/api.ts when the local budget file is absent and handlers['get-remote-files']() returns falsy, meaning the list of remote files could not be fetched from the sync server. Tagged with code 'network-failure'. The API cannot proceed to find a file with the given groupId/syncId without the remote listing.

Source

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

    }
  }
};

handlers['api/download-budget'] = async function ({ syncId, password }) {
  const { id: currentId } = prefs.getPrefs() || {};
  if (currentId) {
    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;

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Verify the sync server URL and credentials (Server password) used by the API init
  2. Test connectivity: GET the server /health endpoint or open the web app against it
  3. Ensure the budget exists on the server (check Settings > Advanced file list)
  4. Retry after network recovery; the code is 'network-failure' so a later retry is safe

Example fix

// before
await api.downloadBudget(syncId);
// after
if (!(await fetch(serverUrl + '/health').then(r => r.ok))) {
  throw new Error('Sync server unreachable: ' + serverUrl);
}
await api.downloadBudget(syncId);
Defensive patterns

Strategy: retry

Validate before calling

const res = await fetch(`${serverUrl}/health`);
if (!res.ok) throw new Error(`Sync server unreachable: ${serverUrl}`);

Try / catch

try {
  await api.downloadBudget(syncId);
} catch (e) {
  if (e.code === 'network-failure') await backoffRetry(() => api.downloadBudget(syncId), 3);
  else throw e;
}

Prevention

When it happens

Trigger: Calling downloadBudget(syncId) from @actual-app/api when the budget does not exist locally and the sync server is unreachable, misconfigured (wrong URL/token), or returns an empty/failed response for get-remote-files.

Common situations: Sync server not running or wrong ACTUAL_SERVER_URL in headless scripts; expired or invalid server password/token; DNS/network outage in CI; self-hosted server behind a broken reverse proxy.

Related errors


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