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
- Retry after a short wait — API-side 5xx with HTML error pages are usually transient
- Check the exact status/body manually: curl -i with the same query string to see what is actually returned
- If a proxy is rewriting responses, bypass it or whitelist caddyserver.com
- 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
- Retry after a minute for API/CDN transient errors
- Whitelist caddyserver.com on content-filtering proxies
- Keep a known-good caddy binary on hand so upgrades are never urgent
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
- download failed: HTTP %d: %s (id=%s)
- server responded with HTTP %d
- problem calling http loader url: %v
- download failed: %v
- secure request failed: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/e5d53a5991e28f05.
Report an issue: GitHub.