{"record":{"id":"59d6f68c952d7215","repo":"louislam/uptime-kuma","slug":"screenshot-delay-must-be-less-than-maxdelayfromi","errorCode":null,"errorMessage":"Screenshot delay must be less than ${maxDelayFromInterval}ms (0.5 × interval)","messagePattern":"Screenshot delay must be less than (.+?)ms \\(0\\.5 × interval\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/model/monitor.js","lineNumber":1767,"sourceCode":"\n        if (this.type === \"real-browser\") {\n            // screenshot_delay validation\n            if (this.screenshot_delay !== undefined && this.screenshot_delay !== null) {\n                const delay = Number(this.screenshot_delay);\n                if (isNaN(delay) || delay < 0) {\n                    throw new Error(\"Screenshot delay must be a non-negative number\");\n                }\n\n                // Must not exceed 0.8 * timeout (page.goto timeout is interval * 1000 * 0.8)\n                const maxDelayFromTimeout = this.interval * 1000 * 0.8;\n                if (delay >= maxDelayFromTimeout) {\n                    throw new Error(`Screenshot delay must be less than ${maxDelayFromTimeout}ms (0.8 × interval)`);\n                }\n\n                // Must not exceed 0.5 * interval to prevent blocking next check\n                const maxDelayFromInterval = this.interval * 1000 * 0.5;\n                if (delay >= maxDelayFromInterval) {\n                    throw new Error(`Screenshot delay must be less than ${maxDelayFromInterval}ms (0.5 × interval)`);\n                }\n            }\n        }\n\n        if (this.type === \"mongodb\" && this.databaseQuery) {\n            // Validate that databaseQuery is valid JSON\n            try {\n                JSON.parse(this.databaseQuery);\n            } catch (error) {\n                throw new Error(`Invalid JSON in database query: ${error.message}`);\n            }\n        }\n    }\n\n    /**\n     * Gets monitor notification of multiple monitor\n     * @param {Array} monitorIDs IDs of monitor to get\n     * @returns {Promise<LooseObject<any>>} object","sourceCodeStart":1749,"sourceCodeEnd":1785,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/model/monitor.js#L1749-L1785","documentation":"Thrown by Monitor.validate() for type \"real-browser\" when screenshot_delay >= interval*1000*0.5. Even though it may fit under the page.goto bound, a delay of half the interval or more risks overlapping the next scheduled heartbeat and blocking the monitor loop.","triggerScenarios":"Save a real-browser monitor whose screenshot_delay passes the 0.8*interval check but is still >= 0.5*interval, e.g. interval=60 and screenshot_delay=31000 (>= 30000ms but < 48000ms). This is the stricter of the two screenshot guards.","commonSituations":"User tunes delay to just under the 0.8 bound and trips this tighter bound instead. Inheriting a delay value from a longer-interval template. Forgetting that the two screenshot guards are independent.","solutions":["Set screenshot_delay to below 0.5 * interval * 1000 ms, e.g. for interval=60s keep delay < 30000ms.","Prefer the smaller of the two bounds (0.5 * interval) as your working ceiling.","Raise interval if a longer delay is genuinely needed."],"exampleFix":"// before\n{ type: \"real-browser\", interval: 60, screenshot_delay: 31000 }\n// after\n{ type: \"real-browser\", interval: 60, screenshot_delay: 25000 }","handlingStrategy":"validation","validationCode":"function delayFitsInterval(delayMs, intervalSec) {\n  return Number(delayMs) < intervalSec * 1000 * 0.5;\n}","typeGuard":"function isDelayUnderIntervalBound(delayMs, intervalSec) {\n  const n = Number(delayMs);\n  return Number.isFinite(n) && n < intervalSec * 1000 * 0.5;\n}","tryCatchPattern":"try {\n  await bean.validate();\n} catch (e) {\n  if (/0\\.5 . interval/.test(e.message)) return badRequest(\"screenshot_delay must be < 0.5 * interval ms\");\n  throw e;\n}","preventionTips":["Treat 0.5 * interval as the working ceiling, not 0.8.","Re-validate the pair on any interval edit."],"tags":["monitor","real-browser","validation","timeout","uptime-kuma"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}