From 9a1d2803a2b1d6d9100c3529b1767599a0a4d13f Mon Sep 17 00:00:00 2001 From: Samuel James <143277412+SamuelSJames@users.noreply.github.com> Date: Sun, 21 Jun 2026 09:21:09 -0400 Subject: [PATCH] Fix monitor ID type mismatch causing all Uptime Kuma statuses to read unknown (#38) heartbeatList/importantHeartbeatList emit monitor IDs as strings (server iterates object keys), while monitorList and the live heartbeat event use numbers. The lastHeartbeat map was keyed by the numeric monitor.id, so string-keyed lookups from heartbeatList/importantHeartbeatList never hit. Co-authored-by: Claude --- backend/src/integrations/uptimeKuma.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/src/integrations/uptimeKuma.ts b/backend/src/integrations/uptimeKuma.ts index 7922d50..94ba388 100644 --- a/backend/src/integrations/uptimeKuma.ts +++ b/backend/src/integrations/uptimeKuma.ts @@ -86,17 +86,20 @@ export const uptimeKuma: IntegrationAdapter = { s.on('monitorList', (list: Record) => { for (const m of Object.values(list)) monitors.set(m.id, m) }) - s.on('importantHeartbeatList', (monitorId: number, beats: Heartbeat[]) => { + s.on('importantHeartbeatList', (monitorId: number | string, beats: Heartbeat[]) => { const latest = beats[beats.length - 1] - if (latest) lastHeartbeat.set(monitorId, latest) + if (latest) lastHeartbeat.set(Number(monitorId), latest) }) // importantHeartbeatList only contains status-change events, so a monitor // that's been continuously up since it was added has no entries there. // heartbeatList carries the regular (non-"important") beat history and is // sent for every monitor, so it's needed to populate those cases too. - s.on('heartbeatList', (monitorId: number, beats: Heartbeat[]) => { + // Uptime Kuma's server emits both with the monitor ID as a string (it + // iterates monitor object keys), unlike monitorList/heartbeat which use + // numeric IDs — coerce so map lookups by numeric monitor.id still hit. + s.on('heartbeatList', (monitorId: number | string, beats: Heartbeat[]) => { const latest = beats[beats.length - 1] - if (latest) lastHeartbeat.set(monitorId, latest) + if (latest) lastHeartbeat.set(Number(monitorId), latest) }) s.on('heartbeat', (beat: Heartbeat & { monitorID: number }) => { lastHeartbeat.set(beat.monitorID, beat)