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
- Verify on the host: ls /sys/class/hwmon — if empty or permission-denied, the platform exposes no readable sensors
- In containers, mount /sys read-only (usually already present; check for overrides)
- If sensors are root-only, run Glance with access to them or accept that temperature is unavailable
- 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
- Ensure /sys/class/hwmon is readable by the Glance process user
- Mount /sys into containers read-only
- Expect no sensors on VMs — configure the System widget without temperature expectations there
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
- usernames must be at least 3 characters
- missing timezone value
- template is required
- invalid first day of week
- invalid body type, must be either 'json' or 'string'
AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15).
Data as JSON: /api/errors/81726bf70778187c.
Report an issue: GitHub.