caddyserver/caddy · error

download and error decoding failed: HTTP %d: %v

Error message

download and error decoding failed: HTTP %d: %v

What it means

The download API returned HTTP >= 400, and when caddy tried to JSON-decode the error body ({status_code, error:{message,id}}) the decode itself failed. So two problems stacked: an HTTP error status and a body that is not the expected JSON error document — typically an HTML error page from a proxy, CDN, or captive portal.

Source

Thrown at cmd/packagesfuncs.go:300

	l.Info("requesting build",
		zap.String("os", qs.Get("os")),
		zap.String("arch", qs.Get("arch")),
		zap.Strings("packages", qs["p"]))
	resp, err := http.Get(fmt.Sprintf("%s?%s", downloadPath, qs.Encode()))
	if err != nil {
		return nil, fmt.Errorf("secure request failed: %v", err)
	}
	if resp.StatusCode >= 400 {
		var details struct {
			StatusCode int `json:"status_code"`
			Error      struct {
				Message string `json:"message"`
				ID      string `json:"id"`
			} `json:"error"`
		}
		err2 := json.NewDecoder(resp.Body).Decode(&details)
		if err2 != nil {
			return nil, fmt.Errorf("download and error decoding failed: HTTP %d: %v", resp.StatusCode, err2)
		}
		return nil, fmt.Errorf("download failed: HTTP %d: %s (id=%s)", resp.StatusCode, details.Error.Message, details.Error.ID)
	}
	return resp, nil
}

func getPluginPackages(modules []moduleInfo) (map[string]pluginPackage, error) {
	pluginPkgs := make(map[string]pluginPackage)
	for _, mod := range modules {
		if mod.goModule.Replace != nil {
			return nil, fmt.Errorf("cannot auto-upgrade when Go module has been replaced: %s => %s",
				mod.goModule.Path, mod.goModule.Replace.Path)
		}
		pluginPkgs[mod.goModule.Path] = pluginPackage{Version: mod.goModule.Version, Path: mod.goModule.Path}
	}
	return pluginPkgs, nil
}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Retry after a short wait — API-side 5xx with HTML error pages are usually transient
  2. Check the exact status/body manually: curl -i with the same query string to see what is actually returned
  3. If a proxy is rewriting responses, bypass it or whitelist caddyserver.com
  4. Check status.caddyserver.com / community channels for build API outages
Defensive patterns

Strategy: retry

Validate before calling

curl -s -o /dev/null -w '%{http_code} %{content_type}\n' 'https://caddyserver.com/api/download?os=linux&arch=amd64'
# expect 200 application/json (or a JSON error); text/html means a proxy/CDN page — investigate

Prevention

When it happens

Trigger: A reverse proxy/CDN in front of caddyserver.com returning an HTML 502/503; a captive portal returning a 400 with an HTML login page; a truncated body causing EOF during decode; a WAF rewriting error responses.

Common situations: caddyserver.com briefly down behind Cloudflare returning HTML error pages; corporate proxy injecting an HTML block page for the download API.

Related errors


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