caddyserver/caddy · error
%s: invalid configuration: %v
Error message
%s: invalid configuration: %v
What it means
After a module is provisioned, LoadModuleByID calls Validate() on Validator implementations to check semantic correctness. Any error is wrapped as '%s: invalid configuration: %v' where %s identifies the module (its caddy.ModuleInfo string). This is the standard error users see when config is syntactically valid JSON but semantically wrong for the module.
Source
Thrown at context.go:450
if err2 != nil {
err = fmt.Errorf("%v; additionally, cleanup: %v", err, err2)
}
}
return nil, fmt.Errorf("provision %s: %v", modInfo, err)
}
}
if validator, ok := val.(Validator); ok {
err = validator.Validate()
if err != nil {
// since the module was already provisioned, make sure we clean up
if cleanerUpper, ok := val.(CleanerUpper); ok {
err2 := cleanerUpper.Cleanup()
if err2 != nil {
err = fmt.Errorf("%v; additionally, cleanup: %v", err, err2)
}
}
return nil, fmt.Errorf("%s: invalid configuration: %v", modInfo, err)
}
}
ctx.moduleInstances[id] = append(ctx.moduleInstances[id], val)
// if the loaded module happens to be an app that can emit events, store it so the
// core can have access to emit events without an import cycle
if ee, ok := val.(eventEmitter); ok {
if _, ok := ee.(App); ok {
ctx.cfg.eventEmitter = ee
}
}
return val, nil
}
// loadModuleInline loads a module from a JSON raw message which decodes to
// a map[string]any, where one of the object keys is moduleNameKeyView on GitHub (pinned to 50e54ee279)
Solutions
- Read the inner error after 'invalid configuration:' — module validators are written to be descriptive
- Adjust the named module's options to satisfy the stated constraint
- If upgrading Caddy revealed this, check the changelog/release notes for the module's new validation rules and migrate the config
- Run `caddy validate --config <file> [--adapter <adapter>]` in CI to catch these before deploy
Example fix
// before
{ "handler": "reverse_proxy", "upstreams": [] }
// after
{ "handler": "reverse_proxy", "upstreams": [ { "dial": "127.0.0.1:8080" } ] } Defensive patterns
Strategy: validation
Validate before calling
// Validate the full config before running — surfaces module Validate() failures cleanly
if err := caddy.ValidateWithAdapter(cfgJSON, caddyfile.Adapter{}); err != nil { // or use CLI
return err
} Try / catch
if _, err := ctx.LoadModuleByID(id, raw); err != nil {
if strings.Contains(err.Error(), "invalid configuration") {
// semantic config error: fix options, not code
}
return err
} Prevention
- Run `caddy validate` on every config change
- Read module docs for semantic constraints (non-empty lists, mutually exclusive options)
- After upgrading Caddy, re-validate existing configs for tightened validators
When it happens
Trigger: A module's Validate() returns an error: contradictory options, empty required collections, out-of-range values, invalid combinations that cannot be expressed as struct tags — e.g. an upstream with no dial addresses, a TLS policy with conflicting client auth settings.
Common situations: Reverse proxy blocks with zero upstreams; matchers with empty patterns; ACME configs combining incompatible options; version changes tightening validation rules so previously-accepted configs now fail after upgrade.
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/daf6e85b47c3403c.
Report an issue: GitHub.