{"record":{"id":"2be52ad774aa84d1","repo":"koala73/worldmonitor","slug":"failed-to-build-overview-snapshot","errorCode":null,"errorMessage":"failed to build overview snapshot","messagePattern":"failed to build overview snapshot","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"consumer-prices-core/src/api/routes/worldmonitor.ts","lineNumber":31,"sourceCode":"  fastify.get('/coverage', async (request, reply) => {\n    const { market = 'ae' } = request.query as { market?: string };\n    try {\n      const data = await buildCoverageSnapshot(market);\n      return reply.send(data);\n    } catch (err) {\n      fastify.log.error(err);\n      return reply.status(500).send({ error: 'failed to build coverage snapshot' });\n    }\n  });\n\n  fastify.get('/overview', async (request, reply) => {\n    const { market = 'ae' } = request.query as { market?: string };\n    try {\n      const data = await buildOverviewSnapshot(market);\n      return reply.send(data);\n    } catch (err) {\n      fastify.log.error(err);\n      return reply.status(500).send({ error: 'failed to build overview snapshot' });\n    }\n  });\n\n  fastify.get('/movers', async (request, reply) => {\n    const { market = 'ae', days = '30' } = request.query as { market?: string; days?: string };\n    try {\n      const data = await buildMoversSnapshot(market, parseInt(days, 10));\n      return reply.send(data);\n    } catch (err) {\n      fastify.log.error(err);\n      return reply.status(500).send({ error: 'failed to build movers snapshot' });\n    }\n  });\n\n  fastify.get('/retailer-spread', async (request, reply) => {\n    const { market = 'ae', basket = 'essentials-ae' } = request.query as {\n      market?: string;\n      basket?: string;","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/koala73/worldmonitor/blob/eeab0a219fce0f02a00603b532dbae9041b934ac/consumer-prices-core/src/api/routes/worldmonitor.ts#L13-L49","documentation":"The Fastify route GET /worldmonitor/overview (query market, default 'ae') returned 500 because buildOverviewSnapshot(market) threw. The overview builder computes essentials/value indices, spread, coverage and freshness via the pg pool in src/db/client.ts, so the underlying throw is typically a database problem — DATABASE_URL unset, an unreachable Postgres, or a SQL/shape regression. fastify.log.error holds the real cause; the response body intentionally does not.","triggerScenarios":"DATABASE_URL missing in the API process; Postgres down or credentials rotated; a migration breaking the overview aggregate queries; a market code with no computed indices reaching an expectation that throws; pool exhausted at max 10.","commonSituations":"Fresh deployment missing the database secret; local dev against a stopped database; nightly index-computation job not having run so downstream aggregation code throws on empty input.","solutions":["Read the fastify error log for the underlying exception","Confirm DATABASE_URL and database reachability from the API host","Check that the index computation pipeline has run for the requested market","Reproduce with buildOverviewSnapshot(market) directly to isolate SQL vs env issues"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"async function overviewDepsOk(): Promise<boolean> {\n  if (!process.env.DATABASE_URL) return false;\n  try { await query('SELECT 1'); return true; } catch { return false; }\n}\n// refuse to serve worldmonitor routes when the dependency is down","typeGuard":null,"tryCatchPattern":"const res = await fetch('/worldmonitor/overview?market=ae');\nif (res.status === 500) {\n  await sleep(1_000);\n  return await fetch('/worldmonitor/overview?market=ae'); // one retry for transient db blips\n}","preventionTips":["Confirm the index-computation job has produced data for the market before exposing the route","Cache the last good overview snapshot and serve it with a staleness marker instead of erroring","Alert on 500 spikes across all snapshot routes at once — that pattern means database, not code"],"tags":["fastify","http-500","database","snapshot","overview"],"backgroundTag":"database-query-failed","analyzedSha":"eeab0a219fce0f02a00603b532dbae9041b934ac","analyzedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-08-31T04:17:50.494Z"}