{"record":{"id":"b6f96500d68bbcb6","repo":"koala73/worldmonitor","slug":"military-live-seed-read-failed","errorCode":null,"errorMessage":"military live seed read failed","messagePattern":"military live seed read failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/worldmonitor/military/v1/list-military-flights.ts","lineNumber":537,"sourceCode":"  try {\n    if (!req.neLat && !req.neLon && !req.swLat && !req.swLon) return emptyResponse();\n    // #6249: a NaN/Infinity corner cannot be normalized into a meaningful\n    // bbox; answer empty instead of letting it reach the relay as garbage.\n    if (!hasFiniteRequestBounds(req)) return emptyResponse();\n    const requestBounds = normalizeBounds(req);\n\n    // The live seed is the source of truth for an authoritatively covered\n    // snapshot. Its value is independent of this request's bbox, so returning\n    // it through the bbox-keyed provider cache would duplicate the same full\n    // snapshot under every viewport key. Use one shared stable snapshot before\n    // judging payload-declared coverage so numeric cursors survive another\n    // edge isolate without making provider recovery globally cacheable.\n    const seeded = await fetchStableLiveSeedSnapshot();\n    if (seeded.status === 'error') {\n      // A Redis command/read failure is not proof the snapshot is missing.\n      // Throw before any provider call so the catch can consult stale data\n      // without turning a Redis outage into per-bbox OpenSky fanout.\n      throw new Error('military live seed read failed');\n    }\n    if (seeded.status === 'hit' && seedCovers(seeded.coverage, requestBounds)) {\n      return paginateResponseForCaller(ctx, seeded.flights, [], requestBounds, req);\n    }\n\n    // A miss, or a hit whose coverage does not contain this request (for\n    // example, a regional snapshot asked about the Americas), needs\n    // request-specific recovery. That response is genuinely bbox-dependent.\n\n    // Quantize bbox to a 1° grid so nearby map views share cache entries.\n    // Precise coordinates caused near-zero hit rate since every pan/zoom created a unique key.\n    // Key by the quantized bbox only. The cached value is the complete\n    // expanded-cell snapshot, so page size and cursor must NOT fragment it —\n    // every page/cursor for the same cell shares one upstream fetch and one\n    // entry, and pagination is applied per-request after retrieval.\n    const cacheKey = `${buildCacheKey(req)}${redistributableOnly ? ':redistributable' : ''}`;\n\n    const fullResult = await cachedFetchJson<ListMilitaryFlightsResponse>(","sourceCodeStart":519,"sourceCodeEnd":555,"githubUrl":"https://github.com/koala73/worldmonitor/blob/9361220cc013571781071f0206e4d80fd14b2f7f/server/worldmonitor/military/v1/list-military-flights.ts#L519-L555","documentation":"listMilitaryFlights first tries a stable live-seed snapshot from Redis via fetchStableLiveSeedSnapshot. If that returns status 'error' — a genuine Redis read/command failure rather than a cache miss — the handler throws 'military live seed read failed' before calling OpenSky, so the outer catch can serve stale data instead of fanning out a per-bbox OpenSky request storm during a Redis outage. The throw is deliberate: ambiguity between 'missing' and 'broken' must not trigger provider recovery that is then globally cached.","triggerScenarios":"fetchStableLiveSeedSnapshot resolves { status: 'error' } because the underlying Redis get (e.g. Upstash HTTP 4xx/5xx, command error, or timeout) failed while handling listMilitaryFlights with any request bbox.","commonSituations":"Upstash outage or credential rotation in production; Redis timeout under load; network partition between the edge isolate and Redis; Redis quota exhaustion returning 429.","solutions":["Restore Redis availability: check Upstash health, credentials, and quotas; the error is a symptom of the seed read failing","Confirm the outer handler's stale-data path serves the last known snapshot instead of hitting OpenSky","Add alerting on seed-read failures so Redis regressions are caught before traffic spikes","If Redis is healthy, inspect fetchStableLiveSeedSnapshot for bugs that misclassify hits/misses as errors"],"exampleFix":"// before\nconst seeded = await fetchStableLiveSeedSnapshot();\nif (seeded.status === 'error') throw new Error('military live seed read failed');\n// after (consumer)\ntry { ... } catch (e) {\n  if (String(e).includes('military live seed read failed')) return serveStaleSnapshot();\n  throw e;\n}","handlingStrategy":"fallback","validationCode":"// Check Redis reachability before requesting military flights\nconst redisOk = await pingRedis();\nif (!redisOk) prewarmStaleSnapshotElsewhere();","typeGuard":"function isSeedReadFailure(e: unknown): boolean {\n  return e instanceof Error && e.message === 'military live seed read failed';\n}","tryCatchPattern":"try {\n  return await listMilitaryFlights(ctx, req);\n} catch (e) {\n  if (isSeedReadFailure(e)) return serveStaleSnapshot(req); // never fan out to OpenSky here\n  throw e;\n}","preventionTips":["Keep a durable stale snapshot available for seed-read outages","Never fall back from this error to per-bbox provider fanout","Alert on seed-read errors to catch Redis outages early","Monitor Upstash quotas and credentials in production"],"tags":["redis","outage","fallback","military-flights"],"backgroundTag":"redis-read-failure","analyzedSha":"9361220cc013571781071f0206e4d80fd14b2f7f","analyzedAt":"2026-09-01T10:32:37.851Z","contentChangedAt":"2026-09-01T10:32:37.851Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}