{"record":{"id":"c38eec83b4bc2512","repo":"glanceapp/glance","slug":"reading-s-w","errorCode":null,"errorMessage":"reading %s: %w","messagePattern":"reading (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/config.go","lineNumber":253,"sourceCode":"\nfunc formatWidgetInitError(err error, w widget) error {\n\treturn fmt.Errorf(\"%s widget: %v\", w.GetType(), err)\n}\n\nvar configIncludePattern = regexp.MustCompile(`(?m)^([ \\t]*)(?:-[ \\t]*)?(?:!|\\$)include:[ \\t]*(.+)$`)\n\nfunc parseYAMLIncludes(mainFilePath string) ([]byte, map[string]struct{}, error) {\n\treturn recursiveParseYAMLIncludes(mainFilePath, nil, 0)\n}\n\nfunc recursiveParseYAMLIncludes(mainFilePath string, includes map[string]struct{}, depth int) ([]byte, map[string]struct{}, error) {\n\tif depth > CONFIG_INCLUDE_RECURSION_DEPTH_LIMIT {\n\t\treturn nil, nil, fmt.Errorf(\"recursion depth limit of %d reached\", CONFIG_INCLUDE_RECURSION_DEPTH_LIMIT)\n\t}\n\n\tmainFileContents, err := os.ReadFile(mainFilePath)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"reading %s: %w\", mainFilePath, err)\n\t}\n\n\tmainFileAbsPath, err := filepath.Abs(mainFilePath)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"getting absolute path of %s: %w\", mainFilePath, err)\n\t}\n\tmainFileDir := filepath.Dir(mainFileAbsPath)\n\n\tif includes == nil {\n\t\tincludes = make(map[string]struct{})\n\t}\n\tvar includesLastErr error\n\n\tmainFileContents = configIncludePattern.ReplaceAllFunc(mainFileContents, func(match []byte) []byte {\n\t\tif includesLastErr != nil {\n\t\t\treturn nil\n\t\t}\n","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/config.go#L235-L271","documentation":"An I/O failure while reading the main config file (or an included file, since recursiveParseYAMLIncludes is invoked per include) during include resolution. The path is included in the message and the underlying os.ReadFile error is wrapped with %w, exposing the OS-level cause (ENOENT, permission, etc.).","triggerScenarios":"Passing a config path to the reader where the file does not exist, is a directory, or the process lacks read permission; also when an !include: directive points at a missing or unreadable file.","commonSituations":"Running glance with a wrong -config path; Docker volume mount missing the config file; include paths that were valid on one machine but not another; file permissions after copying configs as a different user.","solutions":["Verify the printed path exists and is spelled correctly (absolute vs relative — relative includes resolve against the including file's directory)","Check read permission on the file for the glance process user (ls -l, chmod/r chown as needed)","In containers, confirm the volume actually mounts the file (docker inspect / exec ls)","If the error names an include target, fix the path in the !include: directive"],"exampleFix":"# before\n!include: ./shared/widgets.yml   # file lives in shared/parts/widgets.yml\n# after\n!include: ./shared/parts/widgets.yml","handlingStrategy":"validation","validationCode":"// Verify readability before loading config\nif info, err := os.Stat(cfgPath); err != nil || info.IsDir() {\n    log.Fatalf(\"config path unusable: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := loadConfig(path); err != nil {\n    if errors.Is(err, fs.ErrNotExist) {\n        log.Fatal(\"config or include file missing: \", err)\n    }\n    log.Fatal(err)\n}","preventionTips":["Use absolute config paths in service definitions","Smoke-test include paths with ls before restart","Mount config files read-only in containers so paths are stable"],"tags":["glance","io","file-not-found","permissions","yaml"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}