{"record":{"id":"339b7214c58889e1","repo":"caddyserver/caddy","slug":"s-app-module-start-v","errorCode":null,"errorMessage":"%s app module: start: %v","messagePattern":"(.+?) app module: start: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"caddy.go","lineNumber":458,"sourceCode":"\t\t}\n\t}()\n\n\t// Start\n\terr = func() error {\n\t\tstarted := make([]string, 0, len(ctx.cfg.apps))\n\t\tfor name, a := range ctx.cfg.apps {\n\t\t\terr := a.Start()\n\t\t\tif err != nil {\n\t\t\t\t// an app failed to start, so we need to stop\n\t\t\t\t// all other apps that were already started\n\t\t\t\tfor _, otherAppName := range started {\n\t\t\t\t\terr2 := ctx.cfg.apps[otherAppName].Stop()\n\t\t\t\t\tif err2 != nil {\n\t\t\t\t\t\terr = fmt.Errorf(\"%v; additionally, aborting app %s: %v\",\n\t\t\t\t\t\t\terr, otherAppName, err2)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn fmt.Errorf(\"%s app module: start: %v\", name, err)\n\t\t\t}\n\t\t\tstarted = append(started, name)\n\t\t}\n\t\treturn nil\n\t}()\n\tif err != nil {\n\t\treturn ctx, err\n\t}\n\tglobalMetrics.configSuccess.Set(1)\n\tglobalMetrics.configSuccessTime.SetToCurrentTime()\n\n\t// TODO: This event is experimental and subject to change.\n\tctx.emitEvent(\"started\", nil)\n\n\t// now that the user's config is running, finish setting up anything else,\n\t// such as remote admin endpoint, config loader, etc.\n\terr = finishSettingUp(ctx, ctx.cfg)\n\treturn ctx, err","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/caddy.go#L440-L476","documentation":"run() iterates the config's apps calling Start(); the first app whose Start() returns an error aborts startup with '<name> app module: start: %v' (e.g. 'http app module: start: ...'). Prior apps are stopped for a clean unwind. The app name is the module namespace of the app (http, tls, pk, or a plugin app).","triggerScenarios":"http app failing to bind configured listen addresses (port in use, permission on <1024, bad unix socket); tls app failing ACME/TLS provider setup; a plugin app whose Start errors; happens on initial load and on config reloads via unsyncedDecodeAndRun.","commonSituations":"Another process (or a second Caddy instance) already bound the port; binding :80/:443 as non-root without setcap; unix socket dir missing or wrong permissions; plugin resource limits (file descriptors) at startup.","solutions":["Read the wrapped %v — for http it usually names the exact address that failed to bind.","Free the conflicting listener (ss -ltnp / lsof -i :<port>) or change the site's port.","For privileged ports: setcap 'cap_net_bind_service=+ep' $(which caddy) or run via a systemd unit with CAP_NET_BIND_SERVICE.","Retry the load/restart after fixing; earlier apps were already unwound automatically."],"exampleFix":"# before: port 80 taken by nginx\nexample.com {\n  bind 0.0.0.0\n}\n\n# after: free the port or move aside\nsystemctl stop nginx && caddy run --config Caddyfile","handlingStrategy":"validation","validationCode":"// Pre-flight: check every listen address is bindable before loading.\nfor _, addr := range listenAddrs {\n    ln, err := net.Listen(\"tcp\", addr)\n    if err != nil {\n        return fmt.Errorf(\"would fail to bind %s: %w\", addr, err)\n    }\n    ln.Close()\n}","typeGuard":null,"tryCatchPattern":"if _, err := caddy.Run(cfg); err != nil {\n    if strings.Contains(err.Error(), \"app module: start:\") {\n        // named app failed; unwrap and fix its resource (port/socket/creds)\n    }\n}","preventionTips":["Reserve ports with a single owner (systemd socket activation or explicit allocation).","Grant cap_net_bind_service instead of running as root for :80/:443.","Run one Caddy instance per host unless ports are explicitly partitioned."],"tags":["caddy","apps","startup","bind","lifecycle"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}