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
- Ensure the push call sends ping in milliseconds as a non-negative number (e.g. Math.max(0, Math.round(durationMs))).
- If you cannot measure ping, omit the ping query parameter entirely (parseFloat yields NaN, `|| null` makes it null, skipping the check).
- Use a sentinel of omitting ping rather than -1 so the validation never trips.
- 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
- Always report ping in milliseconds, not microseconds/nanoseconds.
- If you cannot measure latency, omit the ping query param rather than sending -1.
- Clamp negative values to 0 in the reporting script.
- Unit-test the push script's ping value against the [0, 1e11] bound.
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
- Unsupported unit (${unit}) for badge duration ${duration}
- Invalid Docker response, is it Docker really a daemon?
- domain_expiry_unsupported_monitor_type
- domain_expiry_unsupported_missing_target
- domain_expiry_unsupported_is_icann
AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12).
Data as JSON: /api/errors/f06f7b4c18810a86.
Report an issue: GitHub.