{"record":{"id":"664f788d3bcba170","repo":"glanceapp/glance","slug":"readfilefromenv-reading-file-from-s-v","errorCode":null,"errorMessage":"readFileFromEnv: reading file from %s: %v","messagePattern":"readFileFromEnv: reading file from (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/config.go","lineNumber":227,"sourceCode":"\n\t\treturn strings.TrimSpace(string(secret)), false, nil\n\tcase configVarTypeFileFromEnv:\n\t\tif !envVariableNamePattern.MatchString(variableName) {\n\t\t\treturn \"\", true, nil\n\t\t}\n\n\t\tfilePath, found := os.LookupEnv(variableName)\n\t\tif !found {\n\t\t\treturn \"\", false, fmt.Errorf(\"readFileFromEnv: environment variable %s not found\", variableName)\n\t\t}\n\n\t\tif !filepath.IsAbs(filePath) {\n\t\t\treturn \"\", false, fmt.Errorf(\"readFileFromEnv: file path %s is not absolute\", filePath)\n\t\t}\n\n\t\tfileContents, err := os.ReadFile(filePath)\n\t\tif err != nil {\n\t\t\treturn \"\", false, fmt.Errorf(\"readFileFromEnv: reading file from %s: %v\", variableName, err)\n\t\t}\n\n\t\treturn strings.TrimSpace(string(fileContents)), false, nil\n\tdefault:\n\t\treturn \"\", true, nil\n\t}\n}\n\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","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/config.go#L209-L245","documentation":"Thrown by parseConfigVariableOfType for {{ file-from-env.NAME }} at the final stage: the env var exists, its value is absolute, but os.ReadFile of that path fails. The error interpolates the env variable NAME (not the path) plus the underlying fs error, so check the env var's value to find the actual path that failed.","triggerScenarios":"API_KEY_FILE=/etc/glance/api_key where the file does not exist, the directory is missing, the Glance process user lacks read permission, or the path points to a directory instead of a file.","commonSituations":"File not yet created at deploy time; file owned by root with 0600 while Glance runs as non-root; volume not mounted into the container at the expected path; typo in the absolute path inside the env var.","solutions":["Verify the path stored in the env var exists and is a regular file: `echo $API_KEY_FILE; ls -l $(eval echo $API_KEY_FILE)`.","Fix permissions: chmod 644 (or chown to the Glance user) so the process can read it.","In containers, confirm the volume/secret mount lands at the exact absolute path the env var names.","Read the wrapped fs error — 'no such file or directory' vs 'permission denied' tells you which fix applies."],"exampleFix":"# before: path typo\n$ export API_KEY_FILE=/etc/glance/api_keys   # directory\n\n# after\n$ export API_KEY_FILE=/etc/glance/api_key     # regular readable file","handlingStrategy":"validation","validationCode":"for var in $(grep -oE '\\{\\{ *file-from-env\\.[A-Za-z_][A-Za-z0-9_]* *\\}\\}' glance.yml | sed -E 's/.*file-from-env\\.([A-Za-z0-9_]+).*/\\1/'); do\n  p=$(printenv \"$var\") || exit 1\n  [ -f \"$p\" ] && [ -r \"$p\" ] || { echo \"cannot read $var -> $p\"; exit 1; }\ndone","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-flight check that every *_FILE target exists and is readable by the service user.","Mount volumes/secrets before Glance starts in containers.","Check wrapped fs error text to distinguish missing file from permission denied."],"tags":["config","filesystem","permissions","files","variables"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}