{"record":{"id":"cdfd3d927a56d9f6","repo":"caddyserver/caddy","slug":"no-handlers-defined","errorCode":null,"errorMessage":"no handlers defined","messagePattern":"no handlers defined","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyevents/app.go","lineNumber":137,"sourceCode":"// Provision sets up the app.\nfunc (app *App) Provision(ctx caddy.Context) error {\n\tapp.logger = ctx.Logger()\n\tapp.subscriptions = make(map[string]map[caddy.ModuleID][]Handler)\n\n\tfor _, sub := range app.Subscriptions {\n\t\tif sub.HandlersRaw == nil {\n\t\t\tcontinue\n\t\t}\n\t\thandlersIface, err := ctx.LoadModule(sub, \"HandlersRaw\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"loading event subscriber modules: %v\", err)\n\t\t}\n\t\tfor _, h := range handlersIface.([]any) {\n\t\t\tsub.Handlers = append(sub.Handlers, h.(Handler))\n\t\t}\n\t\tif len(sub.Handlers) == 0 {\n\t\t\t// pointless to bind without any handlers\n\t\t\treturn fmt.Errorf(\"no handlers defined\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Start runs the app.\nfunc (app *App) Start() error {\n\tfor _, sub := range app.Subscriptions {\n\t\tif err := app.Subscribe(sub); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tapp.started = true\n\n\treturn nil\n}","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyevents/app.go#L119-L155","documentation":"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.","triggerScenarios":"An events subscription whose handlers array is present but empty: Caddyfile 'on <event> {}' with nothing inside, or JSON \"handlers\": [].","commonSituations":"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.","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."],"exampleFix":"// before (caddyfile)\n{\n    events {\n        on tls cert_obtained {}\n    }\n}\n\n// after\n{\n    events {\n        on tls cert_obtained {\n            handler exec {\n                command echo obtained\n            }\n        }\n    }\n}","handlingStrategy":"validation","validationCode":"// templating guard: emit subscription only when handlers exist\n{{if .Handlers}}\n{\n    events {\n        on {{.Event}} {\n            {{range .Handlers}}handler {{.}}\n            {{end}}\n        }\n    }\n}\n{{end}}","typeGuard":null,"tryCatchPattern":"if err := caddy.Validate(cfg); err != nil {\n    if strings.Contains(err.Error(), \"no handlers defined\") {\n        // delete the empty subscription or add a handler, then re-validate\n    }\n    return err\n}","preventionTips":["Never commit an 'on <event> {}' block with no body.","Make templates omit empty subscriptions entirely.","Run caddy validate on rendered configs, not just templates."],"tags":["events","validation","configuration"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}