{"record":{"id":"dd914636b36a4365","repo":"glanceapp/glance","slug":"template-is-required","errorCode":null,"errorMessage":"template is required","messagePattern":"template is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/glance/widget-custom-api.go","lineNumber":65,"sourceCode":"\tcompiledTemplate  *template.Template           `yaml:\"-\"`\n\tCompiledHTML      template.HTML                `yaml:\"-\"`\n}\n\nfunc (widget *customAPIWidget) initialize() error {\n\twidget.withTitle(\"Custom API\").withCacheDuration(1 * time.Hour)\n\n\tif err := widget.CustomAPIRequest.initialize(); err != nil {\n\t\treturn fmt.Errorf(\"initializing primary request: %v\", err)\n\t}\n\n\tfor key := range widget.Subrequests {\n\t\tif err := widget.Subrequests[key].initialize(); err != nil {\n\t\t\treturn fmt.Errorf(\"initializing subrequest %q: %v\", key, err)\n\t\t}\n\t}\n\n\tif widget.Template == \"\" {\n\t\treturn errors.New(\"template is required\")\n\t}\n\n\tcompiledTemplate, err := template.New(\"\").Funcs(customAPITemplateFuncs).Parse(widget.Template)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing template: %w\", err)\n\t}\n\n\twidget.compiledTemplate = compiledTemplate\n\n\treturn nil\n}\n\nfunc (widget *customAPIWidget) update(ctx context.Context) {\n\tcompiledHTML, err := fetchAndRenderCustomAPIRequest(\n\t\twidget.CustomAPIRequest, widget.Subrequests, widget.Options, widget.compiledTemplate,\n\t)\n\tif !widget.canContinueUpdateAfterHandlingErr(err) {\n\t\treturn","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-custom-api.go#L47-L83","documentation":"Unless hide-mountpoints-by-default is set, Glance enumerates partitions with gopsutil's disk.Partitions(false) (physical filesystems only, on Linux it parses /proc/self/mounts filtered to real fs types). Failure is wrapped as 'getting filesystems: %v' and collected; the widget then shows only explicitly configured mountpoints.","triggerScenarios":"disk.Partitions(false) errors — most commonly /proc/self/mounts (or /etc/mtab fallback) being unreadable, or on macOS/Windows the system enumeration API failing. Skipped entirely when hide-mountpoints-by-default: true.","commonSituations":"Containers with /proc masked or a read-only bogus /etc/mtab; chroots and minimal environments; occasionally duplicate or malformed lines in /proc/mounts after heavy bind-mount usage.","solutions":["Check the source file directly: cat /proc/self/mounts (Linux) — if unreadable, fix procfs mounting","If you only want specific mounts anyway, set hide-mountpoints-by-default: true and list mountpoints explicitly — this bypasses disk.Partitions() entirely","In containers, ensure /proc is mounted read-only and not masked","Inspect the wrapped gopsutil error in Glance logs for the exact cause"],"exampleFix":"// before (glance.yml)\n- type: system\n  # relies on auto-discovery of all partitions\n// after: skip disk.Partitions() and list mounts explicitly\n- type: system\n  hide-mountpoints-by-default: true\n  mountpoints:\n    /:\n      name: root\n    /mnt/data:\n      name: data","handlingStrategy":"validation","validationCode":"// avoid disk.Partitions() entirely when its sources may be unavailable\nif hideByDefault {\n    // only explicitly configured mountpoints are queried\n} else if filesystems, err := disk.Partitions(false); err != nil {\n    log.Printf(\"filesystem enumeration failed: %v\", err)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use hide-mountpoints-by-default: true with an explicit mountpoints list in locked-down environments","Keep /proc mounted and readable in containers","Treat enumeration failure as degradation: explicitly configured mountpoints still render"],"tags":["go","gopsutil","disk","filesystems","containers"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}