{"record":{"id":"7e10a6a3550a72f3","repo":"glanceapp/glance","slug":"readfilefromenv-file-path-s-is-not-absolute","errorCode":null,"errorMessage":"readFileFromEnv: file path %s is not absolute","messagePattern":"readFileFromEnv: file path (.+?) is not absolute","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/config.go","lineNumber":222,"sourceCode":"\t\tsecretPath := filepath.Join(\"/run/secrets\", variableName)\n\t\tsecret, err := os.ReadFile(secretPath)\n\t\tif err != nil {\n\t\t\treturn \"\", false, fmt.Errorf(\"reading secret file: %v\", err)\n\t\t}\n\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]*(.+)$`)","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/config.go#L204-L240","documentation":"Thrown by parseConfigVariableOfType for {{ file-from-env.NAME }} when the env var NAME exists but its value is not an absolute path (does not start with /). This is an explicit security guard: relative paths would resolve against Glance's working directory, making file reads dependent on where the process happens to run.","triggerScenarios":"API_KEY_FILE=keys/api.key (relative), API_KEY_FILE=./token, or a value with leading whitespace/tilde like ~/secret — filepath.IsAbs returns false and the error fires.","commonSituations":"Setting the *_FILE variable with a relative path in a compose file or shell; using ~ shorthand which Go's filepath treats as relative; values quoted with accidental leading spaces.","solutions":["Set the env var to an absolute path: API_KEY_FILE=/etc/glance/api_key.","Replace ~ with the full home directory path (/home/user/...).","Check for leading/trailing whitespace or quotes around the value in compose/systemd definitions."],"exampleFix":"# before\n$ export API_KEY_FILE=secrets/api_key\n\n# after\n$ export API_KEY_FILE=/etc/glance/secrets/api_key","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\") || { echo \"not set: $var\"; exit 1; }\n  case \"$p\" in /*) ;; *) echo \"$var must be absolute, got: $p\"; exit 1;; esac\ndone","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always use leading-slash absolute paths in *_FILE variables.","Expand ~ manually; Go's filepath treats it as relative."],"tags":["config","path","validation","security","environment"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}