koala73/worldmonitor · error

failed to build overview snapshot

Error message

failed to build overview snapshot

What it means

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.

Source

Thrown at consumer-prices-core/src/api/routes/worldmonitor.ts:31

  fastify.get('/coverage', async (request, reply) => {
    const { market = 'ae' } = request.query as { market?: string };
    try {
      const data = await buildCoverageSnapshot(market);
      return reply.send(data);
    } catch (err) {
      fastify.log.error(err);
      return reply.status(500).send({ error: 'failed to build coverage snapshot' });
    }
  });

  fastify.get('/overview', async (request, reply) => {
    const { market = 'ae' } = request.query as { market?: string };
    try {
      const data = await buildOverviewSnapshot(market);
      return reply.send(data);
    } catch (err) {
      fastify.log.error(err);
      return reply.status(500).send({ error: 'failed to build overview snapshot' });
    }
  });

  fastify.get('/movers', async (request, reply) => {
    const { market = 'ae', days = '30' } = request.query as { market?: string; days?: string };
    try {
      const data = await buildMoversSnapshot(market, parseInt(days, 10));
      return reply.send(data);
    } catch (err) {
      fastify.log.error(err);
      return reply.status(500).send({ error: 'failed to build movers snapshot' });
    }
  });

  fastify.get('/retailer-spread', async (request, reply) => {
    const { market = 'ae', basket = 'essentials-ae' } = request.query as {
      market?: string;
      basket?: string;

View on GitHub (pinned to eeab0a219f)

Solutions

  1. Read the fastify error log for the underlying exception
  2. Confirm DATABASE_URL and database reachability from the API host
  3. Check that the index computation pipeline has run for the requested market
  4. Reproduce with buildOverviewSnapshot(market) directly to isolate SQL vs env issues
Defensive patterns

Strategy: retry

Validate before calling

async function overviewDepsOk(): Promise<boolean> {
  if (!process.env.DATABASE_URL) return false;
  try { await query('SELECT 1'); return true; } catch { return false; }
}
// refuse to serve worldmonitor routes when the dependency is down

Try / catch

const res = await fetch('/worldmonitor/overview?market=ae');
if (res.status === 500) {
  await sleep(1_000);
  return await fetch('/worldmonitor/overview?market=ae'); // one retry for transient db blips
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21). Data as JSON: /api/errors/2be52ad774aa84d1. Report an issue: GitHub.