caddyserver/caddy · error
server %s: setting up route handlers: %v
Error message
server %s: setting up route handlers: %v
What it means
During provisioning, Caddy loads and provisions the handler modules of every route in servers.<name>.routes (ProvisionHandlers). If any handler module fails to load or provision (bad options, unknown module, failed setup), provisioning stops with this message naming the server. This is the most common wrapper for handler-level config errors.
Source
Thrown at modules/caddyhttp/app.go:372
if srv.PacketConnWrappersRaw != nil {
vals, err := ctx.LoadModule(srv, "PacketConnWrappersRaw")
if err != nil {
return fmt.Errorf("loading packet conn wrapper modules: %v", err)
}
// if any wrappers were configured, they come before the QUIC handshake;
// unlike TLS above, there is no QUIC placeholder
for _, val := range vals.([]any) {
srv.packetConnWrappers = append(srv.packetConnWrappers, val.(caddy.PacketConnWrapper))
}
}
// pre-compile the primary handler chain, and be sure to wrap it in our
// route handler so that important security checks are done, etc.
primaryRoute := emptyHandler
if srv.Routes != nil {
err := srv.Routes.ProvisionHandlers(ctx, app.Metrics)
if err != nil {
return fmt.Errorf("server %s: setting up route handlers: %v", srvName, err)
}
primaryRoute = srv.Routes.Compile(emptyHandler)
}
srv.primaryHandlerChain = srv.wrapPrimaryRoute(primaryRoute)
// pre-compile the error handler chain
if srv.Errors != nil {
err := srv.Errors.Routes.Provision(ctx)
if err != nil {
return fmt.Errorf("server %s: setting up error handling routes: %v", srvName, err)
}
srv.errorHandlerChain = srv.Errors.Routes.Compile(errorEmptyHandler)
}
// provision the named routes (they get compiled at runtime)
for name, route := range srv.NamedRoutes {
err := route.Provision(ctx, app.Metrics)
if err != nil {View on GitHub (pinned to 50e54ee279)
Solutions
- Read the chained %v error — it identifies the handler module and the failing option
- Fix that handler's config (module ID, option names, value formats)
- Run `caddy adapt` then `caddy validate` to catch it before deploy
Example fix
// before
{"handler":"reverse_proxy","to":"http://backend":8080} // malformed
// after
{"handler":"reverse_proxy","upstreams":[{"dial":"localhost:8080"}]} Defensive patterns
Strategy: try-catch
Validate before calling
if err := caddy.Validate(cfgJSON); err != nil { return err } // exercises handler provisioning Try / catch
// when embedding Caddy
err := caddy.Run(cfg)
if err != nil && strings.Contains(err.Error(), "setting up route handlers") {
log.Printf("handler config error on server config; check wrapped cause: %v", err)
} Prevention
- Always run `caddy adapt` + `caddy validate` in CI on every config change
- Generate JSON from typed structs instead of hand-writing it
- Upgrade Caddy/plugins together and re-validate, since option names change
When it happens
Trigger: Any handler module error under servers.<name>.routes: e.g. a reverse_proxy with an unparseable upstream URL, a nonexistent handler module ID, a file_server with an invalid option, a subroute whose handlers fail.
Common situations: Typos in module names or option fields in hand-written JSON; option renames between Caddy/plugin versions; Caddyfile snippets that adapt to invalid JSON.
Related errors
- server %s: %v
- server %s: setting up error handling routes: %v
- server %s: setting up named route '%s' handlers: %v
- unknown object ID '%s'
- loading new config: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/f76f5b856152ddd2.
Report an issue: GitHub.