prometheus/node_exporter · error

couldn't get clocksources

Error message

couldn't get clocksources: %w

What it means

After successfully opening sysfs, the time collector calls fs.ClockSources() to enumerate /sys/devices/system/clocksource/... entries. Any read error (missing directory, unreadable files, parse failure) is wrapped as 'couldn't get clocksources: %w'. The scrape fails rather than emitting partial clocksource metrics.

Solutions

  1. Check that /sys/devices/system/clocksource exists on the host.
  2. Review MAC policy (SELinux/AppArmor) denials for sysfs reads by the exporter process.
  3. Run the collector on the host instead of a restricted container if the kernel does not expose clocksources.
  4. Disable the time collector on kernels lacking clocksource support.
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.ReadDir("/sys/devices/system/clocksource"); err != nil {
    // kernel does not expose clocksources; skip time collector
}

Try / catch

if err := c.Update(ch); err != nil {
    var wrapped string = err.Error()
    if strings.Contains(wrapped, "couldn't get clocksources") {
        logger.Warn("clocksource metrics unavailable on this kernel", "err", err)
        return
    }
    return err
}

Prevention

When it happens

Trigger: timeCollector.update when fs.ClockSources() returns an error — e.g. /sys/devices/system/clocksource absent (virtualized kernels), or individual clocksource/clockevent attributes unreadable.

Common situations: Minimal/VM kernels compiled without clocksource sysfs exposure, security-hardened images hiding /sys/devices, or selinux/apparmor policies denying reads of sysfs attributes.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at collector/time_linux.go:34

package collector

import (
	"fmt"
	"strconv"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/procfs/sysfs"
)

func (c *timeCollector) update(ch chan<- prometheus.Metric) error {
	fs, err := sysfs.NewFS(*sysPath)
	if err != nil {
		return fmt.Errorf("failed to open procfs: %w", err)
	}

	clocksources, err := fs.ClockSources()
	if err != nil {
		return fmt.Errorf("couldn't get clocksources: %w", err)
	}
	c.logger.Debug("in Update", "clocksources", fmt.Sprintf("%v", clocksources))

	for i, clocksource := range clocksources {
		is := strconv.Itoa(i)
		for _, cs := range clocksource.Available {
			ch <- c.clocksourcesAvailable.mustNewConstMetric(1.0, is, cs)
		}
		ch <- c.clocksourceCurrent.mustNewConstMetric(1.0, is, clocksource.Current)
	}
	return nil
}

View on GitHub (pinned to 17ddd77c59)