{"record":{"id":"f0a7b6007c628c3a","repo":"caddyserver/caddy","slug":"loading-dynamic-config-from-t-v","errorCode":null,"errorMessage":"loading dynamic config from %T: %v","messagePattern":"loading dynamic config from %T: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"caddy.go","lineNumber":670,"sourceCode":"\t\t\t\t\t\terr = runLoadedConfig(loadedConfig)\n\t\t\t\t\t\tif errors.Is(err, errSameConfig) {\n\t\t\t\t\t\t\tlogger.Info(\"dynamically-loaded config was unchanged; will retry\")\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\t\tif !timer.Stop() {\n\t\t\t\t\t\t\t<-timer.C\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlogger.Info(\"stopping dynamic config loading\")\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}()\n\t\t} else {\n\t\t\t// if no LoadDelay is provided, will load config synchronously\n\t\t\tloadedConfig, err := val.(ConfigLoader).LoadConfig(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"loading dynamic config from %T: %v\", val, err)\n\t\t\t}\n\t\t\t// do this in a goroutine so current config can finish being loaded; otherwise deadlock\n\t\t\tgo func() { _ = runLoadedConfig(loadedConfig) }()\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ConfigLoader is a type that can load a Caddy config. If\n// the return value is non-nil, it must be valid Caddy JSON;\n// if nil or with non-nil error, it is considered to be a\n// no-op load and may be retried later.\ntype ConfigLoader interface {\n\tLoadConfig(Context) ([]byte, error)\n}\n\n// Stop stops running the current configuration.","sourceCodeStart":652,"sourceCodeEnd":688,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/caddy.go#L652-L688","documentation":"Thrown when the dynamic config loader module implements ConfigLoader and its LoadConfig(ctx) returns an error in the synchronous path (no LoadDelay configured). The message includes %T, the concrete loader module type, so you can identify which loader failed.","triggerScenarios":"admin.config.load is set, LoadDelay is 0/unset, and val.(ConfigLoader).LoadConfig(ctx) returns a non-nil error — e.g. the HTTP loader got a non-200 response, or a custom loader could not fetch/decode its payload.","commonSituations":"Config pulled from a remote URL at startup where the endpoint is down, returns invalid Caddy JSON, or requires auth that was not configured. Because it fires synchronously, Caddy startup aborts.","solutions":["Check which loader type appears in the message and inspect that module's LoadConfig error semantics","For the http loader: verify the URL, network reachability, TLS trust, and that the body is valid Caddy JSON","Set a load_delay so loading happens asynchronously and a transient fetch failure does not abort startup","Test the remote config payload with `caddy validate --adapter json --config <file>` or `curl` first"],"exampleFix":"// before\n{\"admin\": {\"config\": {\"load\": {\"http\": {\"url\": \"http://cfg.internal/current\"}}}}}\n// after (retry-friendly async load)\n{\"admin\": {\"config\": {\"load_delay\": \"5s\", \"load\": {\"http\": {\"url\": \"http://cfg.internal/current\"}}}}}","handlingStrategy":"fallback","validationCode":"// for the http loader: health-check the config endpoint before Caddy starts\nresp, err := http.Get(cfgURL)\nif err != nil || resp.StatusCode != 200 {\n    log.Fatal(\"remote config unavailable\")\n}\nbody, _ := io.ReadAll(resp.Body)\nif err := json.Valid(body); ! err { log.Fatal(\"remote config is not valid JSON\") }","typeGuard":null,"tryCatchPattern":"if err := runLoad(); err != nil {\n    if strings.Contains(err.Error(), \"loading dynamic config from\") {\n        // fall back to last-known-good config file instead of aborting\n    }\n}","preventionTips":["Set load_delay so sync failures don't abort startup","Serve config from a highly available endpoint with retries","Keep a last-known-good config on disk as fallback"],"tags":["dynamic-config","config-loader","startup","network"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}