{"record":{"id":"fdbdb74f2dee14e1","repo":"caddyserver/caddy","slug":"no-admin-server","errorCode":null,"errorMessage":"no admin server","messagePattern":"no admin server","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"admin.go","lineNumber":740,"sourceCode":"\t}\n}\n\nfunc adminPathAllowed(reqPath, allowedPath string) bool {\n\tif allowedPath == \"\" || allowedPath == \"/\" {\n\t\treturn strings.HasPrefix(reqPath, allowedPath)\n\t}\n\tif reqPath == allowedPath {\n\t\treturn true\n\t}\n\tif strings.HasSuffix(allowedPath, \"/\") {\n\t\treturn strings.HasPrefix(reqPath, allowedPath)\n\t}\n\treturn strings.HasPrefix(reqPath, allowedPath+\"/\")\n}\n\nfunc stopAdminServer(srv *http.Server) error {\n\tif srv == nil {\n\t\treturn fmt.Errorf(\"no admin server\")\n\t}\n\ttimeout := 10 * time.Second\n\tctx, cancel := context.WithTimeoutCause(context.Background(), timeout, fmt.Errorf(\"stopping admin server: %ds timeout\", int(timeout.Seconds())))\n\tdefer cancel()\n\terr := srv.Shutdown(ctx)\n\tif err != nil {\n\t\tif cause := context.Cause(ctx); cause != nil && errors.Is(err, context.DeadlineExceeded) {\n\t\t\terr = cause\n\t\t}\n\t\treturn fmt.Errorf(\"shutting down admin server: %v\", err)\n\t}\n\tLog().Named(\"admin\").Info(\"stopped previous server\", zap.String(\"address\", srv.Addr))\n\treturn nil\n}\n\n// AdminRouter is a type which can return routes for the admin API.\ntype AdminRouter interface {\n\tRoutes() []AdminRoute","sourceCodeStart":722,"sourceCodeEnd":758,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/admin.go#L722-L758","documentation":"stopAdminServer guards against being handed a nil *http.Server when shutting down the previous admin endpoint during a config change. In practice this is an internal invariant — the admin server pointer must exist to be stopped — and nil here indicates a bookkeeping bug or a custom embedder calling it with no server running.","triggerScenarios":"Caddy internals calling stopAdminServer(nil) during config replacement when no admin server was ever started (e.g. admin disabled via 'admin off' followed by a config that enables remote admin); library users invoking unexported paths via unsafe tricks.","commonSituations":"Configs mixing 'admin off' and later remote admin enabling in the same process; extremely rare with stock binaries — if seen, likely a bug worth reporting upstream.","solutions":["If admin was disabled ('admin off'), keep it disabled across config changes or fully re-enable it rather than toggling mid-process","Update to the latest Caddy patch release; nil-server shutdown paths have been hardened over time","If reproducible on a stock binary, open an upstream bug with the config sequence"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid toggling 'admin off' and admin on/off across in-process config changes","Report reproducible nil-server cases upstream with the config sequence"],"tags":["admin-api","internal","shutdown","configuration"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}