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

  1. Read the chained %v error — it identifies the handler module and the failing option
  2. Fix that handler's config (module ID, option names, value formats)
  3. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/f76f5b856152ddd2. Report an issue: GitHub.