{"record":{"id":"f7617eda32b708e4","repo":"actualbudget/actual","slug":"network-failure-f7617e","errorCode":"network-failure","errorMessage":"Could not get remote files","messagePattern":"Could not get remote files","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/api.ts","lineNumber":194,"sourceCode":"    }\n  }\n};\n\nhandlers['api/download-budget'] = async function ({ syncId, password }) {\n  const { id: currentId } = prefs.getPrefs() || {};\n  if (currentId) {\n    await handlers['close-budget']();\n  }\n\n  const budgets = await handlers['get-budgets']();\n  const localBudget = budgets.find(b => b.groupId === syncId);\n  let remoteBudget: RemoteFile;\n\n  // Load a remote file if we could not find the file locally\n  if (!localBudget) {\n    const files = await handlers['get-remote-files']();\n    if (!files) {\n      throw withErrorCode(\n        new Error('Could not get remote files'),\n        'network-failure',\n      );\n    }\n    const file = files.find(f => f.groupId === syncId);\n    if (!file) {\n      throw withErrorCode(\n        new Error(\n          `Budget \"${syncId}\" not found. Check the sync id of your budget in the Advanced section of the settings page.`,\n        ),\n        'budget-not-found',\n      );\n    }\n\n    remoteBudget = file;\n  }\n\n  const activeFile = remoteBudget ? remoteBudget : localBudget;","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/api.ts#L176-L212","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the sync server URL and credentials (Server password) used by the API init","Test connectivity: GET the server /health endpoint or open the web app against it","Ensure the budget exists on the server (check Settings > Advanced file list)","Retry after network recovery; the code is 'network-failure' so a later retry is safe"],"exampleFix":"// before\nawait api.downloadBudget(syncId);\n// after\nif (!(await fetch(serverUrl + '/health').then(r => r.ok))) {\n  throw new Error('Sync server unreachable: ' + serverUrl);\n}\nawait api.downloadBudget(syncId);","handlingStrategy":"retry","validationCode":"const res = await fetch(`${serverUrl}/health`);\nif (!res.ok) throw new Error(`Sync server unreachable: ${serverUrl}`);","typeGuard":null,"tryCatchPattern":"try {\n  await api.downloadBudget(syncId);\n} catch (e) {\n  if (e.code === 'network-failure') await backoffRetry(() => api.downloadBudget(syncId), 3);\n  else throw e;\n}","preventionTips":["Verify server URL and credentials before running headless scripts","Add a health-check probe at script start","Retry with backoff on network-failure (idempotent download)","Monitor sync-server uptime in CI environments"],"tags":["network","sync-server","api"],"backgroundTag":"sync-server-unreachable","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}