You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
GET https://api.worldmonitor.app/api/health 401 (Unauthorized)
[App] Refresh health-freshness failed: Error: health freshness fetch failed: 401
Repeats every 60s per open tab (REFRESH_INTERVALS.healthFreshness = 60_000, scheduled with runImmediately: true for ALL variants including happy — src/App.ts:1971). Each failure is also reported through the Sentry-instrumented fetch → Sentry noise.
Root cause
#4715 (merged 2026-07-04) gated detailed /api/health behind an operator/enterprise key server-side, but never swept the dashboard client caller.api/health.js now returns:
{"error":"API key required","hint":"Detailed health requires an operator/enterprise API key. Public status: /api/health?compact=1"}
with WWW-Authenticate: ApiKey realm="worldmonitor-health".
The dashboard client src/services/health-freshness.ts:80 still defaults to the bare, now-gated /api/health and sends no key (correctly — it's an anonymous browser). #4715's diff touched only api/health.js, docs, and server tests — zero client files.
This is the same class as the classify-event 4xx flood (#4779 → #4865 → fix #4869): server-side gating without a client-caller sweep. Issue #4856 caught the advertised status endpoint (api-catalog + Link rel=status) but not this in-app caller.
Impact (beyond console noise)
The seed-health → data-freshness pipeline is silently dead for every visitor since the gate deployed: refreshDataFreshnessFromHealth() throws before dataFreshness.recordSeedHealth(), so panel freshness/staleness indicators never receive seed-health state (STALE_SEED, REDIS_DOWN outage flagging, etc.).
Fix direction
/api/health?compact=1 is public (probed 200 anon) and returns {status, summary, checkedAt, problems} where problems entries carry the same per-check shape (status, records, seedAgeMin, maxStaleMin) under the same check names the client already maps via HEALTH_CHECK_SOURCE_MAP. So:
Point health-freshness.ts at ?compact=1 and adapt the parser: treat problems as the degraded subset, mark all other mapped sources OK (checks absent from problems are healthy by construction).
Preserve the existing REDIS_DOWN/503 body-first handling (health-freshness.ts:89-102).
Symptom
Opening https://worldmonitor.app/desktop (any variant, any anonymous user) floods the console with:
Repeats every 60s per open tab (
REFRESH_INTERVALS.healthFreshness = 60_000, scheduled withrunImmediately: truefor ALL variants including happy —src/App.ts:1971). Each failure is also reported through the Sentry-instrumented fetch → Sentry noise.Root cause
#4715 (merged 2026-07-04) gated detailed
/api/healthbehind an operator/enterprise key server-side, but never swept the dashboard client caller.api/health.jsnow returns:{"error":"API key required","hint":"Detailed health requires an operator/enterprise API key. Public status: /api/health?compact=1"}with
WWW-Authenticate: ApiKey realm="worldmonitor-health".The dashboard client
src/services/health-freshness.ts:80still defaults to the bare, now-gated/api/healthand sends no key (correctly — it's an anonymous browser). #4715's diff touched onlyapi/health.js, docs, and server tests — zero client files.This is the same class as the classify-event 4xx flood (#4779 → #4865 → fix #4869): server-side gating without a client-caller sweep. Issue #4856 caught the advertised status endpoint (api-catalog +
Link rel=status) but not this in-app caller.Impact (beyond console noise)
The seed-health → data-freshness pipeline is silently dead for every visitor since the gate deployed:
refreshDataFreshnessFromHealth()throws beforedataFreshness.recordSeedHealth(), so panel freshness/staleness indicators never receive seed-health state (STALE_SEED, REDIS_DOWN outage flagging, etc.).Fix direction
/api/health?compact=1is public (probed 200 anon) and returns{status, summary, checkedAt, problems}whereproblemsentries carry the same per-check shape (status, records, seedAgeMin, maxStaleMin) under the same check names the client already maps viaHEALTH_CHECK_SOURCE_MAP. So:health-freshness.tsat?compact=1and adapt the parser: treatproblemsas the degraded subset, mark all other mapped sources OK (checks absent fromproblemsare healthy by construction).health-freshness.ts:89-102).Evidence
/api/health→ 401 + WWW-Authenticate;?compact=1→ 200 with problems payload.git show --stat 59e34e607(fix(security): require auth for detailed health metadata #4715): nosrc/files.api/health.js:782-807; client:src/services/health-freshness.ts:80; scheduler:src/App.ts:1971,src/config/variants/base.ts:42.