louislam/uptime-kuma · error · Error

Invalid ping value. Must be between 0 and ${MAX_PING_MS} ms.

Error message

Invalid ping value. Must be between 0 and ${MAX_PING_MS} ms.

What it means

Thrown by the push monitor endpoint (router.all('/api/push/:pushToken')) when the `ping` query parameter is present and falls outside [0, 100000000000] ms (0 to ~3.17 years). The bound exists so the value fits both BIGINT and FLOAT(20,2) columns. The catch block returns this as HTTP 404 with `{ok:false, msg}`.

Source

Thrown at server/routers/api-router.js:59

        result.type = "entryPage";
        result.entryPage = server.entryPage;
    }
    response.json(result);
});

router.all("/api/push/:pushToken", async (request, response) => {
    try {
        let pushToken = request.params.pushToken;
        let msg = request.query.msg || "OK";
        let ping = parseFloat(request.query.ping) || null;
        let statusString = request.query.status || "up";
        const statusFromParam = statusString === "up" ? UP : DOWN;

        // Validate ping value - max 100 billion ms (~3.17 years)
        // Fits safely in both BIGINT and FLOAT(20,2)
        const MAX_PING_MS = 100000000000;
        if (ping !== null && (ping < 0 || ping > MAX_PING_MS)) {
            throw new Error(`Invalid ping value. Must be between 0 and ${MAX_PING_MS} ms.`);
        }

        let monitor = await R.findOne("monitor", " push_token = ? AND active = 1 ", [pushToken]);

        if (!monitor) {
            throw new Error("Monitor not found or not active.");
        }

        const previousHeartbeat = await Monitor.getPreviousHeartbeat(monitor.id);

        let isFirstBeat = true;

        let bean = R.dispense("heartbeat");
        bean.time = R.isoDateTimeMillis(dayjs.utc());
        bean.monitor_id = monitor.id;
        bean.ping = ping;
        bean.msg = msg;
        bean.downCount = previousHeartbeat?.downCount || 0;

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Ensure the push call sends ping in milliseconds as a non-negative number (e.g. Math.max(0, Math.round(durationMs))).
  2. If you cannot measure ping, omit the ping query parameter entirely (parseFloat yields NaN, `|| null` makes it null, skipping the check).
  3. Use a sentinel of omitting ping rather than -1 so the validation never trips.
  4. Validate and clamp ping in your reporting script before the HTTP call.

Example fix

// before
fetch(`${url}/api/push/${token}?status=up&msg=OK&ping=${process.hrtime.bigint()}`) // ns, way over limit

// after
const pingMs = Math.max(0, Math.round(durationNs / 1e6));
fetch(`${url}/api/push/${token}?status=up&msg=OK&ping=${pingMs}`)
Defensive patterns

Strategy: validation

Validate before calling

// Clamp ping to the valid range before pushing
const MAX_PING_MS = 100000000000;
const ping = (rawPing == null || isNaN(Number(rawPing))) ? null : Math.min(Math.max(0, Number(rawPing)), MAX_PING_MS);

Type guard

function isValidPing(ping) {
  return ping == null || (typeof ping === 'number' && !isNaN(ping) && ping >= 0 && ping <= 100000000000);
}

Prevention

When it happens

Trigger: A push-type monitor agent calls /api/push/<token>?ping=<value> with a negative ping, or a ping larger than 100 billion ms. Commonly caused by passing the wrong unit (microseconds, nanoseconds) or a miscomputed/garbage value.

Common situations: Custom push script reports ping in nanoseconds or microseconds; a probe reports -1 as 'unknown'; a unit conversion bug multiplies milliseconds by 1000; a misconfigured agent emits a sentinel like -1 on failure.

Related errors


AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12). Data as JSON: /api/errors/f06f7b4c18810a86. Report an issue: GitHub.