{"record":{"id":"11877c8498249e32","repo":"glanceapp/glance","slug":"readfilefromenv-environment-variable-s-not-found","errorCode":null,"errorMessage":"readFileFromEnv: environment variable %s not found","messagePattern":"readFileFromEnv: environment variable (.+?) not found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/config.go","lineNumber":218,"sourceCode":"\t\t}\n\n\t\treturn v, false, nil\n\tcase configVarTypeSecret:\n\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 {","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/config.go#L200-L236","documentation":"Thrown by parseConfigVariableOfType for {{ file-from-env.NAME }} expressions: NAME is looked up as an environment variable whose VALUE is a file path, and this error means NAME itself is not set in the environment. It is the env-lookup stage of the two-step indirection (env var → path → read file).","triggerScenarios":"glance.yml contains {{ file-from-env.API_KEY_FILE }} and API_KEY_FILE is unset in the Glance process environment, even if the target file exists on disk.","commonSituations":"Using the file-from-env indirection for secret files at custom paths but forgetting to export the *_FILE variable in systemd/docker; env var set in the interactive shell but not in the service unit; typo in the variable name.","solutions":["Export the environment variable pointing at the file: `export API_KEY_FILE=/etc/glance/api_key`.","Add it to the systemd unit Environment=, docker-compose environment:, or the container env.","Verify spelling/case of the variable name in {{ file-from-env.X }}.","Confirm the variable is set for the service user, not just your login shell (`systemctl show-environment`, `docker exec env`)."],"exampleFix":"# systemd unit (before)\n[Service]\nExecStart=/usr/bin/glance --config /etc/glance/glance.yml\n\n# after\n[Service]\nEnvironment=API_KEY_FILE=/etc/glance/api_key\nExecStart=/usr/bin/glance --config /etc/glance/glance.yml","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  printenv \"$var\" >/dev/null || { echo \"file-from-env variable not set: $var\"; exit 1; }\ndone","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat *_FILE variables as required service configuration; declare them in the unit/compose file.","Verify with `docker exec <ctr> env | grep _FILE=` that the indirection variable actually reached the process."],"tags":["config","environment","variables","files","secrets"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}