{"record":{"id":"062e3696d72c9db3","repo":"actualbudget/actual","slug":"network-failure-062e36","errorCode":"network-failure","errorMessage":"Authentication failed: server offline or unreachable","messagePattern":"Authentication failed: server offline or unreachable","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/main.ts","lineNumber":312,"sourceCode":"    if ('sessionToken' in config && config.sessionToken) {\n      // Session token authentication\n      await runHandler(handlers['subscribe-set-token'], {\n        token: config.sessionToken,\n      });\n      // Validate the token\n      const user = await runHandler(handlers['subscribe-get-user'], undefined);\n      if (!user || user.tokenExpired === true) {\n        // Clear invalid token\n        await runHandler(handlers['subscribe-set-token'], { token: '' });\n        throw withErrorCode(\n          new Error('Authentication failed: invalid or expired session token'),\n          'token-expired',\n        );\n      }\n      if (user.offline === true) {\n        // Clear token since we can't validate\n        await runHandler(handlers['subscribe-set-token'], { token: '' });\n        throw withErrorCode(\n          new Error('Authentication failed: server offline or unreachable'),\n          'network-failure',\n        );\n      }\n    } else if ('password' in config && config.password) {\n      const result = await runHandler(handlers['subscribe-sign-in'], {\n        password: config.password,\n      });\n      if (result?.error) {\n        // `result.error` is already a machine-readable slug (e.g.\n        // 'invalid-password', 'network-failure')\n        throw withErrorCode(\n          new Error(`Authentication failed: ${result.error}`),\n          result.error,\n        );\n      }\n    }\n  } else {","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/main.ts#L294-L330","documentation":"During init(), after validating the stored token, the code checks user.offline. If the server reports itself offline (or unreachable when validating), the token is cleared and this error is thrown with code 'network-failure'. It signals the sync server could not be reached or is in an offline state, not a bad credential.","triggerScenarios":"Calling init() with a token-based config when 'subscribe-get-user' returns offline:true — server down, wrong URL/port, DNS failure, or the server explicitly set to offline mode.","commonSituations":"Sync server not started or crashed; misconfigured server URL in client settings; firewall/proxy blocking the server; self-hosted server behind an unreachable host in remote environments.","solutions":["Check the sync server is running and reachable at the configured URL (curl the server health endpoint)","Correct the server URL in the client configuration","Check network/firewall/proxy rules between client and server","If the server intentionally runs offline, reconfigure the client for local-only use or restore server connectivity"],"exampleFix":"// before\nawait init({ URL: 'http://localhost:5007', TOKEN }); // wrong port\n// after\nawait init({ URL: 'http://localhost:5006', TOKEN }); // correct sync-server port","handlingStrategy":"retry","validationCode":"// Probe the server before init\nconst res = await fetch(`${serverUrl}/health`, { method: 'GET' }).catch(() => null);\nif (!res || !res.ok) {\n  throw new Error(`Sync server unreachable at ${serverUrl}`);\n}","typeGuard":"function isNetworkFailureError(e: unknown): e is Error & { code: 'network-failure' } {\n  return e instanceof Error && (e as { code?: string }).code === 'network-failure';\n}","tryCatchPattern":"try {\n  await init({ URL: serverUrl, TOKEN });\n} catch (e) {\n  if (isNetworkFailureError(e)) {\n    await delay(2000);\n    return init({ URL: serverUrl, TOKEN }); // single bounded retry after connectivity check\n  }\n  throw e;\n}","preventionTips":["Health-check the sync server URL before calling init","Verify port (default 5006) and protocol (http/https) in the client config","Distinguish 'network-failure' from 'token-expired': only the former is retryable","Alert on server uptime if clients depend on sync; self-hosted servers behind proxies need keepalive checks"],"tags":["network","sync-server","connectivity","authentication"],"backgroundTag":"server-unreachable","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}