{"record":{"id":"b46a7164092bc47a","repo":"actualbudget/actual","slug":"no-sync-server-configured-b46a71","errorCode":null,"errorMessage":"No sync server configured.","messagePattern":"No sync server configured\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/preferences/app.ts","lineNumber":247,"sourceCode":"\n  await _saveMetadataPrefs(prefsToSet);\n  return 'ok';\n}\n\nasync function loadMetadataPrefs(): Promise<MetadataPrefs> {\n  return _getMetadataPrefs();\n}\n\nasync function saveServerPrefs({ prefs }: { prefs: Record<string, string> }) {\n  const userToken = await asyncStorage.getItem('user-token');\n  if (!userToken) {\n    return { error: 'not-logged-in' };\n  }\n\n  try {\n    const serverConfig = getServer();\n    if (!serverConfig) {\n      throw new Error('No sync server configured.');\n    }\n    await post(serverConfig.SIGNUP_SERVER + '/server-prefs', {\n      token: userToken,\n      prefs,\n    });\n  } catch (err) {\n    if (err instanceof PostError) {\n      return {\n        error: err.reason || 'network-failure',\n      };\n    }\n\n    throw err;\n  }\n\n  return {};\n}\n","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/preferences/app.ts#L229-L265","documentation":"Thrown by saveServerPrefs when the local budget file has no sync server configured. Before syncing server-side preferences to the server via POST /server-prefs, it calls getServer(); if it returns null the user is operating in local-only mode (no server URL set), so there is no endpoint to push prefs to and the method throws instead of making a doomed network call.","triggerScenarios":"Calling the saveServerPrefs method (e.g. via the app API or changing global/server prefs from the UI) while no sync server URL is configured — typically in a local-only budget that has never gone through 'Sign in to server' or bootstrap, or after the server URL was removed/cleared from the prefs.","commonSituations":"Developers scripting against the API with a purely local budget; users switching from server-synced to local-only usage and then trying to save server prefs; fresh CI environments where the sync-server config step was skipped; desktop installs where the server URL was cleared after a budget reset.","solutions":["Configure a sync server URL (bootstrap/login with a server) before calling saveServerPrefs — check getServer() or the config first","If local-only use is intended, skip saveServerPrefs entirely and persist prefs locally via savePrefs instead","Call saveServerPrefs only after a successful login that returns a user-token and server config","Handle the thrown error in the caller and surface a 'no sync server' prompt to the user"],"exampleFix":"// before\nawait app.saveServerPrefs({ prefs });\n// after\nimport { getServer } from './server-config';\nif (getServer()) {\n  await app.saveServerPrefs({ prefs });\n} else {\n  await app.savePrefs({ localPrefs });\n}","handlingStrategy":"try-catch","validationCode":"import { getServer } from './server-config';\nif (!getServer()) {\n  throw new Error('Cannot save server prefs: no sync server configured.');\n}\nconst hasToken = (await asyncStorage.getItem('user-token')) != null;\nif (!hasToken) throw new Error('Cannot save server prefs: not logged in.');","typeGuard":"function hasSyncServer(cfg: ReturnType<typeof getServer> | null): cfg is NonNullable<ReturnType<typeof getServer>> {\n  return cfg != null && typeof cfg.SIGNUP_SERVER === 'string' && cfg.SIGNUP_SERVER.length > 0;\n}","tryCatchPattern":"try {\n  await app.saveServerPrefs({ prefs });\n} catch (err) {\n  if (err instanceof Error && err.message === 'No sync server configured.') {\n    // fall back to local prefs storage\n    await app.savePrefs({ prefs });\n  } else {\n    throw err;\n  }\n}","preventionTips":["Check getServer() (or the server URL pref) before any server-pref operation","Treat local-only budgets as a distinct mode and route pref writes to local storage","Only call saveServerPrefs after a successful login/bootstrap flow","Surface the missing-server state in UI before allowing pref-saving actions"],"tags":["sync","configuration","network"],"backgroundTag":"missing-sync-server-config","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}