caddyserver/caddy · error
no handlers defined
Error message
no handlers defined
What it means
In the events app, a subscription with a non-nil HandlersRaw that loads to zero handlers is rejected: binding a subscription with no handlers would be pointless work. Provision fails immediately rather than silently ignoring the subscription.
Source
Thrown at modules/caddyevents/app.go:137
// Provision sets up the app.
func (app *App) Provision(ctx caddy.Context) error {
app.logger = ctx.Logger()
app.subscriptions = make(map[string]map[caddy.ModuleID][]Handler)
for _, sub := range app.Subscriptions {
if sub.HandlersRaw == nil {
continue
}
handlersIface, err := ctx.LoadModule(sub, "HandlersRaw")
if err != nil {
return fmt.Errorf("loading event subscriber modules: %v", err)
}
for _, h := range handlersIface.([]any) {
sub.Handlers = append(sub.Handlers, h.(Handler))
}
if len(sub.Handlers) == 0 {
// pointless to bind without any handlers
return fmt.Errorf("no handlers defined")
}
}
return nil
}
// Start runs the app.
func (app *App) Start() error {
for _, sub := range app.Subscriptions {
if err := app.Subscribe(sub); err != nil {
return err
}
}
app.started = true
return nil
}View on GitHub (pinned to 50e54ee279)
Solutions
- Add at least one handler inside the subscription block, or
- Delete the whole subscription block if it is no longer needed.
- Guard templating so empty-handler subscriptions are omitted entirely rather than emitted empty.
Example fix
// before (caddyfile)
{
events {
on tls cert_obtained {}
}
}
// after
{
events {
on tls cert_obtained {
handler exec {
command echo obtained
}
}
}
} Defensive patterns
Strategy: validation
Validate before calling
// templating guard: emit subscription only when handlers exist
{{if .Handlers}}
{
events {
on {{.Event}} {
{{range .Handlers}}handler {{.}}
{{end}}
}
}
}
{{end}} Try / catch
if err := caddy.Validate(cfg); err != nil {
if strings.Contains(err.Error(), "no handlers defined") {
// delete the empty subscription or add a handler, then re-validate
}
return err
} Prevention
- Never commit an 'on <event> {}' block with no body.
- Make templates omit empty subscriptions entirely.
- Run caddy validate on rendered configs, not just templates.
When it happens
Trigger: An events subscription whose handlers array is present but empty: Caddyfile 'on <event> {}' with nothing inside, or JSON "handlers": [].
Common situations: Templated configs that render an empty handlers list when a variable is empty; commented-out handlers leaving an empty block; incremental edits where the handler was deleted but the subscription shell remained.
Related errors
- invalid action type
- no identifiers configured
- include and exclude must not intersect, but found %s in both
- unrecognized log level: %s
- module name not specified with key '%s' in %+v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/cdfd3d927a56d9f6.
Report an issue: GitHub.