{"record":{"id":"ab3591bcd7aa18dd","repo":"actualbudget/actual","slug":"health-check-failed-server-responded-to-health-ch","errorCode":null,"errorMessage":"Health check failed: Server responded to health check with status ${status}","messagePattern":"Health check failed: Server responded to health check with status (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/sync-server/src/scripts/health-check.ts","lineNumber":27,"sourceCode":"  if (\n    typeof response === 'object' &&\n    response !== null &&\n    'status' in response &&\n    typeof response.status === 'string'\n  ) {\n    return response.status;\n  }\n\n  return undefined;\n}\n\nfetch(`${protocol}://${hostname}:${config.get('port')}/health`)\n  .then(response => response.json())\n  .then(response => {\n    const status = getHealthStatus(response);\n\n    if (status !== 'UP') {\n      throw new Error(\n        'Health check failed: Server responded to health check with status ' +\n          status,\n      );\n    }\n  })\n  .catch(err => {\n    console.log('Health check failed:', err);\n    process.exit(1);\n  });\n","sourceCodeStart":9,"sourceCodeEnd":37,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/scripts/health-check.ts#L9-L37","documentation":"Thrown by the health-check script when it fetches /health, parses the JSON, and getHealthStatus returns something other than 'UP'. The status (e.g. 'DOWN' or 'DEGRADED') is embedded in the message; the script's catch handler logs and exits non-zero so orchestrators mark the server unhealthy.","triggerScenarios":"Running the health-check script against a server whose /health reports DOWN — e.g. the account database is unreachable, migrations failed, or the sync server is up but its internal dependencies are broken.","commonSituations":"Docker/Kubernetes health probes failing during startup before the DB is ready; misconfigured sqlite path making the server report DOWN; using the script against the wrong port or a different service that answers with non-standard health JSON.","solutions":["Read the reported status and server logs to find why /health reports DOWN (usually DB access).","Verify the account database path/permissions in the sync server config.","Retry after migrations/startup complete; add startup grace periods to your orchestrator.","Confirm the script targets the correct host/port where the Actual sync server listens."],"exampleFix":"// before\nHealth check failed: Server responded to health check with status DOWN\n// after\n# fix DB path, then\nyarn workspace @actual-app/sync-server health-check   # status UP, exit 0","handlingStrategy":"retry","validationCode":"// only run the health check after the server is listening\nawait waitForPort(config.get('port'), { timeoutMs: 30000 });\n// then: const res = await fetch(`http://host:${port}/health`); await res.json();","typeGuard":"function isHealthCheckFailure(err: unknown): err is Error {\n  return err instanceof Error && err.message.startsWith('Health check failed:');\n}","tryCatchPattern":"const run = async (retries = 5) => {\n  for (let i = 0; i < retries; i++) {\n    try { return await healthCheck(); }\n    catch (err) {\n      if (isHealthCheckFailure(err) && i < retries - 1) { await sleep(5000); continue; }\n      throw err;\n    }\n  }\n};","preventionTips":["Add startup grace periods so probes do not run before the DB/migrations are ready.","Verify the account DB path and permissions whenever /health reports DOWN.","Point probes at the configured port, not a default.","Alert on health-check failures and inspect server logs for the root cause."],"tags":["health-check","ops","sync-server","availability"],"backgroundTag":"health-check-failed","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}