{"record":{"id":"01a02058df0b18ce","repo":"actualbudget/actual","slug":"getsyncerror-error-id","errorCode":null,"errorMessage":"getSyncError(error, id)","messagePattern":"getSyncError\\(error, id\\)","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/api.ts","lineNumber":175,"sourceCode":"  }\n\n  batchPromise.resolve();\n  batchPromise = null;\n};\n\nhandlers['api/load-budget'] = async function ({ id }) {\n  const { id: currentId } = prefs.getPrefs() || {};\n\n  if (currentId !== id) {\n    connection.send('start-load');\n    const { error } = await handlers['load-budget']({ id });\n\n    if (!error) {\n      connection.send('finish-load');\n    } else {\n      connection.send('show-budgets');\n\n      throw withErrorCode(new Error(getSyncError(error, id)), error);\n    }\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) {","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/api.ts#L157-L193","documentation":"Thrown by the api/load-budget handler in packages/loot-core/src/server/api.ts when loading a budget for the @actual-app/api fails with a sync error. The raw error reason is passed through getSyncError() (packages/loot-core/src/shared/errors.ts:141) which maps reasons like out-of-sync-migrations, invalid-schema, budget-not-found, and clock-drift to human-readable messages. The thrown error keeps the original reason code via withErrorCode.","triggerScenarios":"Calling loadBudget(id) from @actual-app/api where the budget needs a sync that fails: budget id not found locally/remotely, database schema newer than app version, migrations out of sync, or device clock drift versus sync server.","commonSituations":"Typo in the budget id passed to loadBudget; opening a budget created by a newer Actual version; system clock wrong (Docker containers, dual-boot machines); budget deleted on server.","solutions":["Verify the budget id via getBudgetFiles()/list budgets on the Advanced settings page","Update Actual to the latest version to match the budget's schema/migrations","Fix the device clock (NTP sync) if the reason is clock-drift","Check the thrown error's code property for the underlying reason and handle each case"],"exampleFix":"// before\nawait api.loadBudget('my-budget');\n// after\ntry {\n  await api.loadBudget(id);\n} catch (e) {\n  if (e.code === 'budget-not-found') id = await promptForValidId();\n  else if (e.code === 'clock-drift') fixSystemClock();\n  else throw e;\n}","handlingStrategy":"try-catch","validationCode":"const files = await api.getBudgetFiles();\nif (!files.some(f => f.id === budgetId)) throw new Error(`Budget ${budgetId} not available locally`);","typeGuard":"function hasErrorCode(e: unknown, code: string): e is { code: string } {\n  return typeof e === 'object' && e !== null && (e as any).code === code;\n}","tryCatchPattern":"try {\n  await api.loadBudget(id);\n} catch (e) {\n  if (hasErrorCode(e, 'budget-not-found')) pickValidBudget();\n  else if (hasErrorCode(e, 'clock-drift')) fixClockAndRetry();\n  else if (hasErrorCode(e, 'invalid-schema')) await updateActual();\n  else throw e;\n}","preventionTips":["Validate budget ids against getBudgetFiles() before loading","Keep Actual up to date across all devices","Keep system clocks NTP-synced","Log e.code to identify the underlying sync reason"],"tags":["sync","budget-load","api"],"backgroundTag":"budget-sync-failed","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}