gotify/server · error
read file for %s_FILE (%s): %w
Error message
read file for %s_FILE (%s): %w
What it means
lookupEnv supports the _FILE convention: if <ENV>_FILE is set, the actual value is read from that file. If os.ReadFile fails, lookupEnv returns the wrapped error 'read file for %s_FILE (%s): %w', which propagates out of config.Get for every parser (parseString, parseInt, parseBool, parseList, parseMap, parseLogLevel).
Source
Thrown at config/parse.go:22
"encoding/csv"
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
)
func lookupEnv(env string) (string, bool, error) {
if raw, ok := os.LookupEnv(env); ok {
return raw, true, nil
}
path, ok := os.LookupEnv(env + "_FILE")
if !ok {
return "", false, nil
}
data, err := os.ReadFile(path)
if err != nil {
return "", false, fmt.Errorf("read file for %s_FILE (%s): %w", env, path, err)
}
return strings.TrimRight(string(data), "\r\n"), true, nil
}
func parseString(target *string, env string) error {
raw, ok, err := lookupEnv(env)
if err != nil {
return err
}
if ok {
*target = raw
}
return nil
}
func parseInt(target *int, env string) error {
raw, ok, err := lookupEnv(env)
if err != nil {View on GitHub (pinned to 14bfc25627)
Solutions
- Verify the file path in <VAR>_FILE exists and is readable inside the runtime environment (ls -l, check the mount).
- Fix the Kubernetes/Docker volume mount so the secret is present at the exact path referenced by _FILE.
- Use an absolute path for _FILE values.
- Handle the error from config.Get at startup and fail fast with a message naming the variable and path.
Example fix
// before API_KEY_FILE=/run/secrets/api_key # file not mounted // after API_KEY_FILE=/run/secrets/api-key # matches the actual volume mount path
Defensive patterns
Strategy: validation
Validate before calling
func assertEnvFileReadable(env string) error {
p, ok := os.LookupEnv(env + "_FILE")
if !ok { return nil }
f, err := os.Open(p)
if err != nil {
return fmt.Errorf("%s_FILE=%s is not readable: %w", env, p, err)
}
return f.Close()
}
// call before config.Get: assertEnvFileReadable("API_KEY") Try / catch
if err := config.Get(&cfg); err != nil {
if m := fileVarRe.FindStringSubmatch(err.Error()); m != nil {
return fmt.Errorf("check secret mount for %s: %w", m[1], err)
}
return err
} Prevention
- Use absolute paths in every <VAR>_FILE and match them exactly to the secret mount
- Verify secret mounts exist at container startup (readiness check that opens the file)
- Keep _FILE and direct env mutually exclusive in your deployment templates
- Fail fast at boot: surface config.Get errors before serving traffic
When it happens
Trigger: Setting an env var like API_KEY_FILE to a path that does not exist or is unreadable, then calling config.Get; the error surfaces on whichever var uses the _FILE mechanism.
Common situations: Docker/Kubernetes secrets mounted at a different path than _FILE points to, secret not mounted (typo in volume mount), file deleted at container start, or relative path resolved against the wrong working directory.
Related errors
- invalid int for %s (%q): %w
- invalid bool for %s (%q): %w
- invalid CSV for %s (%q): %w
- cannot read config file %s: %w
- cannot delete internal application
AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05).
Data as JSON: /api/errors/d9964e31d7ae2a6c.
Report an issue: GitHub.