caddyserver/caddy · error
loading new config: %v
Error message
loading new config: %v
What it means
The new config was accepted by changeConfig but unsyncedDecodeAndRun failed while preparing or running it — module loading, provisioning, validation, or app startup returned an error. Caddy restores the previous raw config and returns 'loading new config' wrapping the root cause. The old config keeps running, making admin-API loads atomic.
Source
Thrown at caddy.go:264
// our old representation of caddy's actual config
err = unsyncedDecodeAndRun(newCfg, true)
if err != nil {
if len(rawCfgJSON) > 0 {
// restore old config state to keep it consistent
// with what caddy is still running; we need to
// unmarshal it again because it's likely that
// pointers deep in our rawCfg map were modified
var oldCfg any
err2 := json.Unmarshal(rawCfgJSON, &oldCfg)
if err2 != nil {
err = fmt.Errorf("%v; additionally, restoring old config: %v", err, err2)
}
rawCfg[rawConfigKey] = oldCfg
} else {
rawCfg[rawConfigKey] = nil
}
return fmt.Errorf("loading new config: %v", err)
}
// success, so update our stored copy of the encoded
// config to keep it consistent with what caddy is now
// running (storing an encoded copy is not strictly
// necessary, but avoids an extra json.Marshal for
// each config change)
rawCfgJSON = newCfg
rawCfgIndex = idx
return nil
}
// readConfig traverses the current config to path
// and writes its JSON encoding to out.
func readConfig(path string, out io.Writer) error {
rawCfgMu.RLock()
defer rawCfgMu.RUnlock()View on GitHub (pinned to 50e54ee279)
Solutions
- Read the wrapped error — it identifies the failing module, field, or listener precisely.
- Pre-validate before applying: caddy validate --config <file> (add --adapter if not JSON).
- Fix the named module/field (correct module ID, free the port, fix TLS settings) and retry the load.
- For custom builds, ensure the required plugin is compiled in (caddy list-modules | grep <name>).
Example fix
# before curl -X POST localhost:2019/load -H 'Content-Type: application/json' --data @broken.json # after: validate first, then load caddy validate --config caddy.json && curl -X POST localhost:2019/load -H 'Content-Type: application/json' --data @caddy.json
Defensive patterns
Strategy: try-catch
Validate before calling
// Dry-run the exact bytes you will POST.
if err := caddy.Validate(cfgBytes); err != nil { // or: caddy validate --config file
return err
} Try / catch
resp, err := client.Post("http://localhost:2019/load", "application/json", bytes.NewReader(cfg))
if err == nil && resp.StatusCode >= 400 {
body, _ := io.ReadAll(resp.Body)
if strings.Contains(string(body), "loading new config") {
// old config still running; fix the named module/field and retry
}
} Prevention
- Run caddy validate --config in CI for every config change.
- Pin plugin versions and rebuild with xcaddy to keep module IDs available.
- Check port availability before deploying configs that bind new listeners.
When it happens
Trigger: POST /load (or PUT/PATCH /config/) with a config that references an unregistered module ID, fails Validate(), binds a port already in use, has invalid TLS/automation policies, or whose app Start() errors. Caddyfile users see the equivalent from 'caddy validate' failures.
Common situations: Deploying a config that uses a module not compiled into the custom build; port conflicts on reload; invalid ACME/TLS settings; schema changes between Caddy versions (renamed fields produce provisioning errors).
Related errors
- unknown object ID '%s'
- decoding request body: %w, at offset %d
- decoding request body: %w
- no traversable path
- path missing
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/3f2b3aa0e897d5fc.
Report an issue: GitHub.