caddyserver/caddy · error

server responded with HTTP %d

Error message

server responded with HTTP %d

What it means

The HTTP config loader (loading the running config over HTTP(S)) treats a final response with status >= 400 as a hard failure, reporting the status code. Because attemptHttpCall already rejects anything outside 200-499 and retries it, the responses that actually reach this check are 4xx ones (404, 401, 403, ...) — client-side errors that retrying will not fix.

Source

Thrown at caddyconfig/httploader.go:114

	url := repl.ReplaceAll(hl.URL, "")
	req, err := http.NewRequestWithContext(ctx, method, url, nil)
	if err != nil {
		return nil, err
	}
	for key, vals := range hl.Headers {
		for _, val := range vals {
			req.Header.Add(repl.ReplaceAll(key, ""), repl.ReplaceKnown(val, ""))
		}
	}

	resp, err := doHttpCallWithRetries(ctx, client, req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("server responded with HTTP %d", resp.StatusCode)
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// adapt the config based on either manually-configured adapter or server's response header
	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())

View on GitHub (pinned to 50e54ee279)

Solutions

  1. curl the exact URL from the Caddy host and inspect status/body; fix the path or endpoint.
  2. If auth is required, configure the loader's 'headers' block (e.g. Authorization bearer token).
  3. Check the config server's logs for why it rejected the request.

Example fix

# before
{
  admin off
  config_loaders {
    http http://cfg.internal/caddy/config
  }
}

# after
{
  admin off
  config_loaders {
    http http://cfg.internal/caddy/config {
      headers Authorization "Bearer {env.CFG_TOKEN}"
    }
  }
}
Defensive patterns

Strategy: retry

Validate before calling

curl -fsS -H "Authorization: Bearer $CFG_TOKEN" "$CONFIG_URL" >/dev/null && echo endpoint-ok || echo endpoint-broken

Try / catch

// if embedding Caddy: treat config-load status errors as non-retryable client errors
if err := loadConfig(ctx); err != nil {
	if strings.Contains(err.Error(), "server responded with HTTP") {
		// 4xx from the config endpoint: fix URL/headers, do not retry blindly
		log.Fatal(err)
	}
	return err
}

Prevention

When it happens

Trigger: Running Caddy with a config URL where the endpoint returns 404 (wrong path), 401/403 (auth required but no/insufficient headers configured), or any 4xx on the first attempt.

Common situations: Centralized config distribution where the config service requires a token not sent; typo in the config URL path; endpoint moved after a config-service upgrade.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/c1b31bae088cbeab. Report an issue: GitHub.