glanceapp/glance · error

readFileFromEnv: reading file from %s: %v

Error message

readFileFromEnv: reading file from %s: %v

What it means

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.

Source

Thrown at internal/glance/config.go:227

		return strings.TrimSpace(string(secret)), false, nil
	case configVarTypeFileFromEnv:
		if !envVariableNamePattern.MatchString(variableName) {
			return "", true, nil
		}

		filePath, found := os.LookupEnv(variableName)
		if !found {
			return "", false, fmt.Errorf("readFileFromEnv: environment variable %s not found", variableName)
		}

		if !filepath.IsAbs(filePath) {
			return "", false, fmt.Errorf("readFileFromEnv: file path %s is not absolute", filePath)
		}

		fileContents, err := os.ReadFile(filePath)
		if err != nil {
			return "", false, fmt.Errorf("readFileFromEnv: reading file from %s: %v", variableName, err)
		}

		return strings.TrimSpace(string(fileContents)), false, nil
	default:
		return "", true, nil
	}
}

func formatWidgetInitError(err error, w widget) error {
	return fmt.Errorf("%s widget: %v", w.GetType(), err)
}

var configIncludePattern = regexp.MustCompile(`(?m)^([ \t]*)(?:-[ \t]*)?(?:!|\$)include:[ \t]*(.+)$`)

func parseYAMLIncludes(mainFilePath string) ([]byte, map[string]struct{}, error) {
	return recursiveParseYAMLIncludes(mainFilePath, nil, 0)
}

View on GitHub (pinned to 91324e8de7)

Solutions

  1. 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)`.
  2. Fix permissions: chmod 644 (or chown to the Glance user) so the process can read it.
  3. In containers, confirm the volume/secret mount lands at the exact absolute path the env var names.
  4. Read the wrapped fs error — 'no such file or directory' vs 'permission denied' tells you which fix applies.

Example fix

# before: path typo
$ export API_KEY_FILE=/etc/glance/api_keys   # directory

# after
$ export API_KEY_FILE=/etc/glance/api_key     # regular readable file
Defensive patterns

Strategy: validation

Validate before calling

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
  p=$(printenv "$var") || exit 1
  [ -f "$p" ] && [ -r "$p" ] || { echo "cannot read $var -> $p"; exit 1; }
done

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15). Data as JSON: /api/errors/664f788d3bcba170. Report an issue: GitHub.