caddyserver/caddy · error
reading environment file
Error message
reading environment file: %v
What it means
loadEnvFromFile wraps a failed os.Open of the --env-file target. The file could not be opened at all — usually missing or unreadable. (Its sibling 'parsing environment file' fires later, for content problems.) Loaded vars are only set if not already present, so the file is purely supplemental.
Solutions
- Verify the path exists and is readable by the caddy process user
- Use an absolute path for --env-file in service units
- Remember existing environment variables win; you can also set vars directly in the unit instead of the file
Example fix
# before ExecStart=/usr/bin/caddy run --config /etc/caddy/Caddyfile --env-file .env # after ExecStart=/usr/bin/caddy run --config /etc/caddy/Caddyfile --env-file /etc/caddy/.env
Defensive patterns
Strategy: validation
Validate before calling
# Ensure the env file exists and is readable before launch:
[ -r /etc/caddy/.env ] || { echo "env file missing/unreadable" >&2; exit 1; }
caddy run --config /etc/caddy/Caddyfile --env-file /etc/caddy/.env Prevention
- Use absolute --env-file paths in service units
- Ship the env file with the config in deployment bundles
- Remember existing environment variables are never overwritten by --env-file
When it happens
Trigger: Running 'caddy run --env-file .env' where .env does not exist in the working directory, or the CLI user lacks read permission on it.
Common situations: Deployments copying configs but not the env file; relative path assumptions in service units with a different WorkingDirectory; permissions tightened on secrets files (which is fine — but then grant the caddy user read access).
Related errors
- reading config from file
- backing up current binary
- checking if default Caddyfile exists
- download succeeded, but unable to clean up backup binary
- making folder for CA database
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/abd33e566f17b793.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/main.go:355
// not in the flag set.
func (f Flags) Float64(name string) float64 {
val, _ := strconv.ParseFloat(f.String(name), 64)
return val
}
// Duration returns the duration representation of the
// flag given by name. It returns false if the flag
// is not a duration type. It panics if the flag is
// not in the flag set.
func (f Flags) Duration(name string) time.Duration {
val, _ := caddy.ParseDuration(f.String(name))
return val
}
func loadEnvFromFile(envFile string) error {
file, err := os.Open(envFile)
if err != nil {
return fmt.Errorf("reading environment file: %v", err)
}
defer file.Close()
envMap, err := parseEnvFile(file)
if err != nil {
return fmt.Errorf("parsing environment file: %v", err)
}
for k, v := range envMap {
// do not overwrite existing environment variables
_, exists := os.LookupEnv(k)
if !exists {
if err := os.Setenv(k, v); err != nil {
return fmt.Errorf("setting environment variables: %v", err)
}
}
}
View on GitHub (pinned to 50e54ee279)