{"record":{"id":"d4e66c2c08d4c83f","repo":"louislam/uptime-kuma","slug":"ntp-server-is-unsynchronized-stratum-16","errorCode":null,"errorMessage":"NTP server is unsynchronized (stratum 16)","messagePattern":"NTP server is unsynchronized \\(stratum 16\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/monitor-types/ntp.js","lineNumber":36,"sourceCode":"        const startTime = dayjs().valueOf();\n\n        if (!monitor.hostname) {\n            throw new Error(\"Hostname is required\");\n        }\n\n        const port = monitor.port || 123;\n        const timeout = (monitor.timeout || 10) * 1000;\n\n        const ntpResult = await this.queryNTP(monitor.hostname, port, timeout);\n\n        heartbeat.ping = dayjs().valueOf() - startTime;\n\n        const { stratum, offset, rootDispersion, refid, roundTripDelay } = ntpResult;\n\n        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        }","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/monitor-types/ntp.js#L18-L54","documentation":"Thrown when the NTP response's stratum byte equals 16. Per RFC 5905, stratum 16 is reserved for 'unsynchronized' — the server's clock is not currently disciplined by a reference source, so its time cannot be trusted. This is checked before the configurable stratum threshold because stratum 16 is a hard failure regardless of policy.","triggerScenarios":"queryNTP resolves, the server replies with a valid >=48-byte packet, parseNTPResponse returns stratum===16. Happens when ntpd/chronyd on the target lost all sources, just started, has no peers, or its system peer was marked unreachable.","commonSituations":"Target server's own NTP daemon is broken (no upstream, firewall blocking outbound 123); freshly rebooted server before sync; GPS/appliance NTP source disconnected; querying a host that is not really an NTP server but happens to answer on UDP 123.","solutions":["On the target, verify the daemon: 'chronyc sources' / 'ntpq -p' and confirm a reachable, selected peer.","Allow outbound NTP (UDP 123) from the target to its upstreams, or point it at reachable internal stratum-1/2 servers.","Wait for the daemon to select a source and re-stabilise (can take minutes).","Point the monitor at a different, known-good NTP source."],"exampleFix":"# on target server, before:\n#   chronyc sources -> 0 sources (^?)\n# fix upstream reachability, then:\nsudo chronyc makestep\n# verify: chronyc tracking  -> 'Stratum' becomes 2/3","handlingStrategy":"try-catch","validationCode":"// Probe the target before relying on the monitor:\n// run: ntpdate -q <host>  or  chronyc -h <host> sources\n// and reject targets reporting stratum 16.","typeGuard":null,"tryCatchPattern":"try { await ntpMonitor.check(monitor, heartbeat, server); }\ncatch (e) { if (/stratum 16/.test(e.message)) { heartbeat.status = DOWN; heartbeat.msg = e.message; } else throw e; }","preventionTips":["Confirm the target daemon has selected a healthy peer (chronyc sources / ntpq -p).","Don't monitor a freshly-restarted NTP server until it converges.","Prefer known-good public or internal stratum-1/2 servers."],"tags":["ntp","time-sync","stratum","uptime-kuma"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}