caddyserver/caddy · error · caddy.APIError
loading config: %v
Error message
loading config: %v
What it means
Returned with HTTP 400 by POST /load when caddy.Load() rejects the (possibly adapted) config body. caddy.Load validates, provisions, and swaps the whole config; failure means the JSON is structurally invalid, a module ID is unknown, or a module's Provision/Validate returned an error. The running configuration is untouched — the load is atomic.
Source
Thrown at caddyconfig/load.go:120
}
}
if len(warnings) > 0 {
respBody, err := json.Marshal(warnings)
if err != nil {
caddy.Log().Named("admin.api.load").Error(err.Error())
}
_, _ = w.Write(respBody) //nolint:gosec // false positive: no XSS here
}
body = result
}
forceReload := r.Header.Get("Cache-Control") == "must-revalidate"
err = caddy.Load(body, forceReload)
if err != nil {
return caddy.APIError{
HTTPStatus: http.StatusBadRequest,
Err: fmt.Errorf("loading config: %v", err),
}
}
// If this request changed the config, clear the last
// config info we have stored, if it is different from
// the original source.
caddy.ClearLastConfigIfDifferent(
r.Header.Get("Caddy-Config-Source-File"),
r.Header.Get("Caddy-Config-Source-Adapter"))
caddy.Log().Named("admin.api").Info("load complete")
return nil
}
// handleAdapt adapts the given Caddy config to JSON and responds with the result.
func (adminLoad) handleAdapt(w http.ResponseWriter, r *http.Request) error {
if r.Method != http.MethodPost {View on GitHub (pinned to 50e54ee279)
Solutions
- Run caddy validate --config <file> [--adapter <name>] against the same config first — it reports the precise validation error
- Validate the JSON syntax locally (jq . config.json) before posting
- Read the error detail in the response body and in the server logs — it names the failing module and field
- If a module is reported unknown, rebuild Caddy with the required plugin (xcaddy build --with ...)
Example fix
// before curl -X POST http://localhost:2019/load -d @broken.json // after caddy validate --config ./broken.json && curl -X POST http://localhost:2019/load -H 'Content-Type: application/json' -d @broken.json
Defensive patterns
Strategy: validation
Validate before calling
// dry-run the exact bytes through the same pipeline first
func safeLoad(ctx context.Context, client *http.Client, cfg []byte) error {
req, _ := http.NewRequestWithContext(ctx, "POST", "http://localhost:2019/load", bytes.NewReader(cfg))
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil { return err }
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("load rejected (%d): %s — validate config first", resp.StatusCode, b)
}
return nil
} Try / catch
if resp.StatusCode == http.StatusBadRequest {
var apiErr struct{ Error string }
json.NewDecoder(resp.Body).Decode(&apiErr)
if strings.Contains(apiErr.Error, "loading config") {
// config rejected: do NOT retry; fix config and re-validate
log.Printf("config rejected: %s", apiErr.Error)
}
} Prevention
- Always run caddy validate on the config file before posting to /load
- Post to /adapt first as a dry-run when using a config adapter
- Pin module availability: build with xcaddy and verify with caddy list-modules in CI
When it happens
Trigger: Posting JSON with syntax errors or wrong schema (e.g. missing apps wrapper); referencing a module that is not compiled into the binary (e.g. dns challenge providers in a custom build); a module failing Validate (e.g. tls automation with no email and no local issuer config); adapter output that is valid JSON but semantically wrong.
Common situations: CI/CD pipelines pushing generated config where a field was renamed between Caddy versions; hand-edited JSON with trailing commas; adapting a Caddyfile that uses a plugin not included in the build; loading config referencing http.handlers.foo in a build without that plugin.
Related errors
- parsing listener address: %v
- must be exactly one listener address; cannot listen on: %s
- indexing config: %v
- %s: %s field must be a string or number
- duplicate ID '%s' found at %s and %s
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/f99e0603b76457eb.
Report an issue: GitHub.