glanceapp/glance · warning

hour-format must be either 12h or 24h

Error message

hour-format must be either 12h or 24h

What it means

Glance calls gopsutil's sensors.SensorsTemperatures() to read thermal sensors. Only a *sensors.Warnings error (partial results, e.g. some sensors unreadable) is tolerated; any other error is wrapped as 'getting sensor readings: %v' and collected. When it fails, no temperature is reported at all.

Source

Thrown at internal/glance/widget-clock.go:28

var clockWidgetTemplate = mustParseTemplate("clock.html", "widget-base.html")

type clockWidget struct {
	widgetBase `yaml:",inline"`
	cachedHTML template.HTML `yaml:"-"`
	HourFormat string        `yaml:"hour-format"`
	Timezones  []struct {
		Timezone string `yaml:"timezone"`
		Label    string `yaml:"label"`
	} `yaml:"timezones"`
}

func (widget *clockWidget) initialize() error {
	widget.withTitle("Clock").withError(nil)

	if widget.HourFormat == "" {
		widget.HourFormat = "24h"
	} else if widget.HourFormat != "12h" && widget.HourFormat != "24h" {
		return errors.New("hour-format must be either 12h or 24h")
	}

	for t := range widget.Timezones {
		if widget.Timezones[t].Timezone == "" {
			return errors.New("missing timezone value")
		}

		if _, err := time.LoadLocation(widget.Timezones[t].Timezone); err != nil {
			return fmt.Errorf("invalid timezone '%s': %v", widget.Timezones[t].Timezone, err)
		}
	}

	widget.cachedHTML = widget.renderTemplate(widget, clockWidgetTemplate)

	return nil
}

func (widget *clockWidget) Render() template.HTML {

View on GitHub (pinned to 91324e8de7)

Solutions

  1. Verify on the host: ls /sys/class/hwmon — if empty or permission-denied, the platform exposes no readable sensors
  2. In containers, mount /sys read-only (usually already present; check for overrides)
  3. If sensors are root-only, run Glance with access to them or accept that temperature is unavailable
  4. Do not set cpu-temp-sensor in config on hosts with no sensor support — it cannot match anything

Example fix

// before (docker run without sys)
docker run -v /:/mnt/host:ro glance
// after: ensure host sysfs is visible to gopsutil
docker run -v /proc:/proc:ro -v /sys:/sys:ro glance
Defensive patterns

Strategy: try-catch

Validate before calling

readings, err := sensors.SensorsTemperatures()
if _, isWarn := err.(*sensors.Warnings); err != nil && !isWarn {
    // hard failure: no temperature data this cycle
    return fmt.Errorf("getting sensor readings: %w", err)
}

Type guard

func isTolerableSensorError(err error) bool {
	_, ok := err.(*sensors.Warnings)
	return err == nil || ok
}

Try / catch

Mirror Glance's own guard: accept *sensors.Warnings (partial data) and only treat other errors as failure. Wrap with %v/%w and collect into an errors.Join-style list rather than aborting the whole system-info report.

Prevention

When it happens

Trigger: sensors.SensorsTemperatures() returns a non-Warnings error — typically the sysfs tree /sys/class/hwmon being unreadable or absent on Linux, or the LmSensors-derived sources failing. The call is skipped entirely on Windows and the BSDs by the runtime.GOOS guard above.

Common situations: Containers without /sys mounted or with sensors masked; stripped-down VMs with no thermal devices; hosts where /sys/class/hwmon exists but files are root-only and Glance runs as a non-root user without read access.

Related errors


AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15). Data as JSON: /api/errors/81726bf70778187c. Report an issue: GitHub.