{"record":{"id":"544da1b0b20db5ce","repo":"louislam/uptime-kuma","slug":"root-dispersion-rootdispersion-tofixed-3-ms-exc","errorCode":null,"errorMessage":"Root dispersion ${rootDispersion.toFixed(3)}ms exceeds threshold ${dispersionThreshold}ms","messagePattern":"Root dispersion (.+?)ms exceeds threshold (.+?)ms","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"server/monitor-types/ntp.js","lineNumber":51,"sourceCode":"        heartbeat.msg = `Stratum: ${stratum}, RefID: ${refid}, Offset: ${offset.toFixed(3)}ms, Delay: ${roundTripDelay.toFixed(3)}ms, Dispersion: ${rootDispersion.toFixed(3)}ms`;\n\n        if (stratum === 16) {\n            throw new Error(\"NTP server is unsynchronized (stratum 16)\");\n        }\n\n        const stratumThreshold = monitor.ntp_stratum_threshold || 5;\n        if (stratum >= stratumThreshold) {\n            throw new Error(`Stratum ${stratum} meets or exceeds threshold ${stratumThreshold}`);\n        }\n\n        const offsetThreshold = monitor.ntp_time_offset_threshold || 1000;\n        if (Math.abs(offset) >= offsetThreshold) {\n            throw new Error(`Time offset ${offset.toFixed(3)}ms exceeds threshold ${offsetThreshold}ms`);\n        }\n\n        const dispersionThreshold = monitor.ntp_root_dispersion_threshold || 500;\n        if (rootDispersion >= dispersionThreshold) {\n            throw new Error(\n                `Root dispersion ${rootDispersion.toFixed(3)}ms exceeds threshold ${dispersionThreshold}ms`\n            );\n        }\n\n        heartbeat.status = UP;\n    }\n\n    /**\n     * Query an NTP server via UDP\n     * @param {string} hostname NTP server hostname or IP\n     * @param {number} port NTP server port (usually 123)\n     * @param {number} timeout Timeout in milliseconds\n     * @returns {Promise<object>} Parsed NTP response data\n     */\n    queryNTP(hostname, port, timeout) {\n        return new Promise((resolve, reject) => {\n            let client = null;\n            let settled = false;","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/monitor-types/ntp.js#L33-L69","documentation":"Thrown when rootDispersion >= monitor.ntp_root_dispersion_threshold (default 500 ms). Root dispersion is the server's reported accumulated measurement error (read as a 32-bit fixed-point at packet offset 8 and converted to ms). High dispersion indicates the server itself is uncertain about its time, independent of the offset to this client.","triggerScenarios":"Server returns a valid packet whose root-dispersion field, converted to ms, meets or exceeds dispersionThreshold. Happens with unstable server chains, recently restarted daemons whose filters haven't converged, or misbehaving appliance servers.","commonSituations":"Default 500 ms threshold too strict for a legitimate distant server; target's dispersion genuinely high due to poor upstream stability; software/appliance NTP reporting inflated dispersion.","solutions":["Raise monitor.ntp_root_dispersion_threshold to a value the target normally stays under.","Switch to a more stable, lower-stratum NTP source.","Confirm the target daemon has had time to converge after restart."],"exampleFix":"// before: monitor.ntp_root_dispersion_threshold = 500\n// after:  monitor.ntp_root_dispersion_threshold = 2000","handlingStrategy":"validation","validationCode":"function validateDispersionThreshold(monitor) {\n  const t = Number(monitor.ntp_root_dispersion_threshold ?? 500);\n  if (!Number.isFinite(t) || t <= 0) throw new Error('ntp_root_dispersion_threshold must be > 0');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Observe the target's typical root dispersion, then set the threshold above it with margin.","Switch to a more stable NTP source if dispersion is persistently high.","Let a restarted daemon converge before alerting."],"tags":["ntp","threshold","config","uptime-kuma"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}