{"record":{"id":"5740af4f9805a030","repo":"actualbudget/actual","slug":"no-sync-server-configured-5740af","errorCode":null,"errorMessage":"No sync server configured.","messagePattern":"No sync server configured\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/encryption/app.ts","lineNumber":79,"sourceCode":"  cloudFileId?: Budget['cloudFileId'];\n  password: string;\n}) {\n  const userToken = await asyncStorage.getItem('user-token');\n\n  if (cloudFileId == null) {\n    cloudFileId = prefs.getPrefs().cloudFileId;\n  }\n\n  let validCloudFileId: NonNullable<Budget['cloudFileId']>;\n  let res: {\n    id: string;\n    salt: string;\n    test: string | null;\n  };\n  try {\n    const serverConfig = getServer();\n    if (!serverConfig) {\n      throw new Error('No sync server configured.');\n    }\n    res = await post(serverConfig.SYNC_SERVER + '/user-get-key', {\n      token: userToken,\n      fileId: cloudFileId,\n    });\n    validCloudFileId = cloudFileId!;\n  } catch (e) {\n    logger.log(e);\n    return { error: { reason: 'network' } };\n  }\n\n  const { id, salt, test: originalTest } = res;\n\n  if (!originalTest) {\n    return { error: { reason: 'old-key-style' } };\n  }\n\n  const test: {","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/encryption/app.ts#L61-L97","documentation":"keyTest validates a password against the key stored on the sync server by POSTing to /user-get-key, so it requires a configured sync server (getServer()). When no server URL is configured it throws 'No sync server configured.' before making any network request.","triggerScenarios":"Calling keyTest (user-test-key handler) in a local-only setup with no server URL set in prefs; the server config was cleared or never entered on the 'no server' path; testing a cloud-file key for a file opened without sync.","commonSituations":"Local-first users enabling encryption without a sync server; config migration losing the server URL; automation running against a budget file downloaded manually rather than via sync.","solutions":["Configure a sync server URL in settings before calling key-test","Only call keyTest for files that are synced from a server; use a local key path otherwise","Check getServer()/prefs for SYNC_SERVER before invoking and branch to local key verification","Re-enter server settings if a config reset wiped the URL"],"exampleFix":"// before\nconst ok = await send('key-test', { password, cloudFileId });\n// after\nif (getServer()) {\n  const ok = await send('key-test', { password, cloudFileId });\n} else {\n  throw new Error('Key testing requires a configured sync server');\n}","handlingStrategy":"validation","validationCode":"const serverConfig = getServer();\nif (!serverConfig || !serverConfig.SYNC_SERVER) {\n  throw new Error('Configure a sync server before testing cloud encryption keys');\n}","typeGuard":"function hasSyncServer(cfg: { SYNC_SERVER?: string } | null): cfg is { SYNC_SERVER: string } {\n  return !!cfg && typeof cfg.SYNC_SERVER === 'string' && cfg.SYNC_SERVER.length > 0;\n}","tryCatchPattern":"try {\n  const valid = await send('key-test', { password, cloudFileId });\n} catch (e) {\n  if (e.message === 'No sync server configured.') {\n    promptUserForServerSettings();\n  } else throw e;\n}","preventionTips":["Only use key-test for files that came from a sync server","Check server config in prefs before enabling cloud-key UI features","Persist the server URL and detect config resets early","For local-only budgets, use local key verification paths instead"],"tags":["encryption","network","configuration","sync-server"],"backgroundTag":"missing-server-config","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}