prometheus/node_exporter · error

only IP address of local NTP server is valid for…

Error message

only IP address of local NTP server is valid for --collector.ntp.server

What it means

NewNtpCollector validates the --collector.ntp.server flag before creating the collector. Unless --collector.ntp.server-is-mine is set, the value must parse as an IP address (net.ParseIP non-nil) and be a loopback address. Hostnames, non-loopback IPs, or arbitrary strings are rejected with this error at startup.

Solutions

  1. Resolve your local NTP server's address and pass it as an IP literal, e.g. --collector.ntp.server=127.0.0.1.
  2. Only if you truly control the server and accept the TTL=1 reachability model, add --collector.ntp.server-is-mine to bypass the loopback check.
  3. Do not use hostnames or public NTP pools (pool.ntp.org); this collector is not designed for them.
  4. If you need generic NTP monitoring, use a different exporter (e.g. an NTP exporter based on beevik/ntp) since this collector is deprecated.

Example fix

// before
//   --collector.ntp.server=pool.ntp.org
// after: local server IP, or explicitly claim the server
//   --collector.ntp.server=192.168.1.1
//   --collector.ntp.server-is-mine
Defensive patterns

Strategy: validation

Validate before calling

// shell: validate the flag value before starting the exporter
SRV="$(grep -Po '(?<=--collector\.ntp\.server=)\S+' <<<'...')"
ipcalc "$SRV" >/dev/null 2>&1 || echo "$SRV is not an IP literal"
python3 -c "import ipaddress,sys; a=ipaddress.ip_address('$SRV'); sys.exit(0 if a.is_loopback else 1)" || echo "$SRV is not loopback"

Prevention

When it happens

Trigger: Starting node_exporter with --collector.ntp.server set to a hostname (e.g. pool.ntp.org), an empty value, a non-IP string, or a public/non-loopback IP, while --collector.ntp.server-is-mine is false.

Common situations: Users copying examples that use NTP pool hostnames; pointing the collector at a remote public NTP server instead of a local one (the collector intentionally requires a local server because it uses IP TTL=1 probes); forgetting that the flag takes an IP, not a DNS name.

Understand the failure class

Background: "unknown output mode", "invalid value for flag", "expects true/false": fixing invalid flag value errors in CLI tools — this error's family across 24 libraries.

Related errors


AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07). Data as JSON: /api/errors/bddf6180e6e2136b. Report an issue: GitHub.

Appendix: source

Thrown at collector/ntp.go:66

)

type ntpCollector struct {
	stratum, leap, rtt, offset, reftime, rootDelay, rootDispersion, sanity typedDesc
	logger                                                                 *slog.Logger
}

func init() {
	registerCollector("ntp", defaultDisabled, NewNtpCollector)
}

// NewNtpCollector returns a new Collector exposing sanity of local NTP server.
// Default definition of "local" is:
// - collector.ntp.server address is a loopback address (or collector.ntp.server-is-mine flag is turned on)
// - the server is reachable with outgoing IP_TTL = 1
func NewNtpCollector(logger *slog.Logger) (Collector, error) {
	ipaddr := net.ParseIP(*ntpServer)
	if !*ntpServerIsLocal && (ipaddr == nil || !ipaddr.IsLoopback()) {
		return nil, fmt.Errorf("only IP address of local NTP server is valid for --collector.ntp.server")
	}

	if *ntpProtocolVersion < 2 || *ntpProtocolVersion > 4 {
		return nil, fmt.Errorf("invalid NTP protocol version %d; must be 2, 3, or 4", *ntpProtocolVersion)
	}

	if *ntpOffsetTolerance < 0 {
		return nil, fmt.Errorf("offset tolerance must be non-negative")
	}

	if *ntpServerPort < 1 || *ntpServerPort > 65535 {
		return nil, fmt.Errorf("invalid NTP port number %d; must be between 1 and 65535 inclusive", *ntpServerPort)
	}

	logger.Warn("This collector is deprecated and will be removed in the next major version release.")
	return &ntpCollector{
		stratum: typedDesc{prometheus.NewDesc(
			prometheus.BuildFQName(namespace, ntpSubsystem, "stratum"),

View on GitHub (pinned to 17ddd77c59)