caddyserver/caddy · error
reading config from file
Error message
reading config from file: %v
What it means
os.ReadFile on the explicitly given --config file failed, wrapped as 'reading config from file'. The underlying error is almost always 'no such file or directory' or 'permission denied' for that exact path.
Solutions
- Verify the path: ls -l <config> from the same user and working directory
- Use an absolute path in --config, especially in service units
- Fix read permissions on the file (and execute permission on parent dirs)
Example fix
# before ExecStart=/usr/bin/caddy run --config Caddyfile # after ExecStart=/usr/bin/caddy run --config /etc/caddy/Caddyfile
Defensive patterns
Strategy: validation
Validate before calling
# Resolve and stat the config before invoking caddy:
CONFIG=$(realpath "$CONFIG")
[ -r "$CONFIG" ] || { echo "cannot read $CONFIG" >&2; exit 1; } Prevention
- Use absolute paths in service units and cron jobs
- Check readability as the same user that runs caddy
When it happens
Trigger: Typo'd or wrong-case path in --config; file exists but the running user lacks read permission; relative path interpreted against an unexpected working directory (systemd, cron).
Common situations: Service units with WorkingDirectory! set so a relative --config resolves wrong; permissions tightened on /etc/caddy; configs generated to a temp path that was cleaned up.
Related errors
- no config file to load; either use --config flag or ensure…
- reading default Caddyfile
- reading environment file
- adapting config using
- backing up current binary
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/961cdc3d608e710c.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/main.go:172
if adapterName != "" && configFile == "" {
return nil, "", "", fmt.Errorf("cannot adapt config without config file (use --config)")
}
// load initial config and adapter
var config []byte
var cfgAdapter caddyconfig.Adapter
var err error
if configFile != "" {
if configFile == "-" {
config, err = io.ReadAll(os.Stdin)
if err != nil {
return nil, "", "", fmt.Errorf("reading config from stdin: %v", err)
}
logger.Info("using config from stdin")
} else {
config, err = os.ReadFile(configFile)
if err != nil {
return nil, "", "", fmt.Errorf("reading config from file: %v", err)
}
logger.Info("using config from file", zap.String("file", configFile))
}
} else if adapterName == "" {
// if the Caddyfile adapter is plugged in, we can try using an
// adjacent Caddyfile by default
cfgAdapter = caddyconfig.GetAdapter("caddyfile")
if cfgAdapter != nil {
config, err = os.ReadFile("Caddyfile")
if errors.Is(err, fs.ErrNotExist) {
// okay, no default Caddyfile; pretend like this never happened
cfgAdapter = nil
} else if err != nil {
// default Caddyfile exists, but error reading it
return nil, "", "", fmt.Errorf("reading default Caddyfile: %v", err)
} else {
// success reading default Caddyfile
configFile = "Caddyfile"View on GitHub (pinned to 50e54ee279)