caddyserver/caddy · error
problem calling http loader url: %v
Error message
problem calling http loader url: %v
What it means
The lowest-level transport failure inside attemptHttpCall: http.Client.Do itself errored (DNS failure, connection refused, TLS handshake error, timeout). It is wrapped with this message and — unless it was the 10th and final attempt — retried by doHttpCallWithRetries; the error escapes only after all retries are exhausted or the context is done.
Source
Thrown at caddyconfig/httploader.go:141
ct := resp.Header.Get("Content-Type")
if hl.Adapter != "" {
ct = "text/" + hl.Adapter
}
result, warnings, err := adaptByContentType(ct, body)
if err != nil {
return nil, err
}
for _, warn := range warnings {
ctx.Logger().Warn(warn.String())
}
return result, nil
}
func attemptHttpCall(client *http.Client, request *http.Request) (*http.Response, error) {
resp, err := client.Do(request) //nolint:gosec // no SSRF; comes from trusted config
if err != nil {
return nil, fmt.Errorf("problem calling http loader url: %v", err)
} else if resp.StatusCode < 200 || resp.StatusCode > 499 {
resp.Body.Close()
return nil, fmt.Errorf("bad response status code from http loader url: %v", resp.StatusCode)
}
return resp, nil
}
func doHttpCallWithRetries(ctx caddy.Context, client *http.Client, request *http.Request) (*http.Response, error) {
var resp *http.Response
var err error
const maxAttempts = 10
for i := range maxAttempts {
resp, err = attemptHttpCall(client, request)
if err != nil && i < maxAttempts-1 {
select {
case <-time.After(time.Millisecond * 500):
case <-ctx.Done():View on GitHub (pinned to 50e54ee279)
Solutions
- Verify reachability from the Caddy host: 'curl -v <config-url>'.
- For self-signed/private-CA endpoints, add 'root_ca' files (and client cert/key if mTLS) to the loader's tls block.
- Increase the loader 'timeout' if the config endpoint is slow.
- Fix boot ordering / add a startup dependency so the config service is up first.
Example fix
# before
http https://cfg.internal/config.json
# after
http https://cfg.internal/config.json {
timeout 60s
tls {
root_ca /etc/caddy/cfg-ca.pem
}
} Defensive patterns
Strategy: retry
Validate before calling
curl -v --connect-timeout 5 "$CONFIG_URL" -o /dev/null # verify DNS, TCP, TLS all work from the Caddy host
Prevention
- Ensure the config service is up before Caddy starts (init/compose depends_on).
- Configure root_ca/client certs for private TLS endpoints; raise the loader timeout for slow endpoints.
When it happens
Trigger: Config URL host not resolving; config server not listening (connection refused); TLS certificate of the config endpoint untrusted by the client's pool; the loader's Timeout too short for a slow endpoint.
Common situations: Boot-order races where Caddy starts before the config service; self-signed TLS on the config server without RootCAPEMFiles configured; restrictive DNS/network policy in containers.
Related errors
- server responded with HTTP %d
- got HTTP %d
- error reading response body: %v
- could not determine zone for domain: %w (domain=%s nameserve
- loading dynamic config from %T: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/f870a6ff421ddb71.
Report an issue: GitHub.