{"record":{"id":"81726bf70778187c","repo":"glanceapp/glance","slug":"hour-format-must-be-either-12h-or-24h","errorCode":null,"errorMessage":"hour-format must be either 12h or 24h","messagePattern":"hour-format must be either 12h or 24h","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/glance/widget-clock.go","lineNumber":28,"sourceCode":"var clockWidgetTemplate = mustParseTemplate(\"clock.html\", \"widget-base.html\")\n\ntype clockWidget struct {\n\twidgetBase `yaml:\",inline\"`\n\tcachedHTML template.HTML `yaml:\"-\"`\n\tHourFormat string        `yaml:\"hour-format\"`\n\tTimezones  []struct {\n\t\tTimezone string `yaml:\"timezone\"`\n\t\tLabel    string `yaml:\"label\"`\n\t} `yaml:\"timezones\"`\n}\n\nfunc (widget *clockWidget) initialize() error {\n\twidget.withTitle(\"Clock\").withError(nil)\n\n\tif widget.HourFormat == \"\" {\n\t\twidget.HourFormat = \"24h\"\n\t} else if widget.HourFormat != \"12h\" && widget.HourFormat != \"24h\" {\n\t\treturn errors.New(\"hour-format must be either 12h or 24h\")\n\t}\n\n\tfor t := range widget.Timezones {\n\t\tif widget.Timezones[t].Timezone == \"\" {\n\t\t\treturn errors.New(\"missing timezone value\")\n\t\t}\n\n\t\tif _, err := time.LoadLocation(widget.Timezones[t].Timezone); err != nil {\n\t\t\treturn fmt.Errorf(\"invalid timezone '%s': %v\", widget.Timezones[t].Timezone, err)\n\t\t}\n\t}\n\n\twidget.cachedHTML = widget.renderTemplate(widget, clockWidgetTemplate)\n\n\treturn nil\n}\n\nfunc (widget *clockWidget) Render() template.HTML {","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-clock.go#L10-L46","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (docker run without sys)\ndocker run -v /:/mnt/host:ro glance\n// after: ensure host sysfs is visible to gopsutil\ndocker run -v /proc:/proc:ro -v /sys:/sys:ro glance","handlingStrategy":"try-catch","validationCode":"readings, err := sensors.SensorsTemperatures()\nif _, isWarn := err.(*sensors.Warnings); err != nil && !isWarn {\n    // hard failure: no temperature data this cycle\n    return fmt.Errorf(\"getting sensor readings: %w\", err)\n}","typeGuard":"func isTolerableSensorError(err error) bool {\n\t_, ok := err.(*sensors.Warnings)\n\treturn err == nil || ok\n}","tryCatchPattern":"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.","preventionTips":["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"],"tags":["go","gopsutil","sensors","linux","containers"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}