{"record":{"id":"9252c90cabcd63cc","repo":"glanceapp/glance","slug":"reading-secret-file-v","errorCode":null,"errorMessage":"reading secret file: %v","messagePattern":"reading secret file: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/config.go","lineNumber":207,"sourceCode":"// When the bool return value is true, it indicates that the caller should use the original value\nfunc parseConfigVariableOfType(variableType, variableName string) (string, bool, error) {\n\tswitch variableType {\n\tcase configVarTypeEnv:\n\t\tif !envVariableNamePattern.MatchString(variableName) {\n\t\t\treturn \"\", true, nil\n\t\t}\n\n\t\tv, found := os.LookupEnv(variableName)\n\t\tif !found {\n\t\t\treturn \"\", false, fmt.Errorf(\"environment variable %s not found\", variableName)\n\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)","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/config.go#L189-L225","documentation":"Thrown by parseConfigVariableOfType for {{ secret.NAME }} expressions when os.ReadFile of /run/secrets/NAME fails (missing file, permission denied, directory absent). Docker's secrets mechanism mounts files under /run/secrets; the value used is the trimmed file contents. The underlying fs error is wrapped with 'reading secret file:'.","triggerScenarios":"glance.yml contains {{ secret.db_password }} but /run/secrets/db_password does not exist on the Glance host, the process lacks read permission, or /run/secrets itself is absent (non-Docker or non-swarm deployment without manually placing the file).","commonSituations":"Running the Docker image without `--secret` / compose `secrets:` mapping; running the binary directly on a host where the secrets dir was never created; file owned by root while Glance runs as a non-root user; secret name typo.","solutions":["Ensure the file exists at exactly /run/secrets/NAME with the secret as its contents (Docker secrets or manual placement: mkdir -p /run/secrets && echo -n 'value' > /run/secrets/NAME).","Verify the process user can read the file (chmod 644 / appropriate ownership).","Check the name inside {{ secret.X }} matches the mounted secret's filename exactly.","In compose, declare and map the secret: secrets: [db_password] under the service plus top-level secrets.","Read the wrapped error — it tells you whether it was 'no such file' vs 'permission denied'."],"exampleFix":"# docker-compose.yml (before)\nservices:\n  glance:\n    configs:\n      - glance.yml   # secret never mounted\n\n# after\nservices:\n  glance:\n    secrets:\n      - db_password\nsecrets:\n  db_password:\n    file: ./db_password.txt","handlingStrategy":"validation","validationCode":"# pre-flight check for every {{ secret.X }} in glance.yml\nmkdir -p /run/secrets\nfor s in $(grep -oE '\\{\\{ *secret\\.[A-Za-z0-9_-]+ *\\}\\}' glance.yml | sed -E 's/.*secret\\.([A-Za-z0-9_-]+).*/\\1/'); do\n  [ -r \"/run/secrets/$s\" ] || { echo \"secret not readable: /run/secrets/$s\"; exit 1; }\ndone","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Map Docker/compose secrets so files land under /run/secrets/<name>.","Make secret files readable by the Glance process user.","Prefer {{ secret.X }} over baking values into glance.yml."],"tags":["config","secrets","docker","filesystem","permissions"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}