caddyserver/caddy · error

download failed: %v

Error message

download failed: %v

What it means

upgradeBuild failed to obtain a custom build from the download API (https://caddyserver.com/api/download). downloadBuild performs an HTTP GET with os/arch and the package list; this wrapper fires on transport errors ('secure request failed: ...') or HTTP >= 400 responses from the API (bad/unknown module, version that doesn't exist, build server error), with the API's decoded message embedded. Note this mechanism requires internet access to caddyserver.com — builds are produced server-side, not locally.

Source

Thrown at cmd/packagesfuncs.go:158

			return caddy.ExitCodeFailedStartup, fmt.Errorf("resolving current executable symlink: %v", err)
		}
		l.Info("this executable is a symlink", zap.String("source", symSource), zap.String("target", thisExecPath))
	}
	l.Info("this executable will be replaced", zap.String("path", thisExecPath))

	// build the request URL to download this custom build
	qs := url.Values{
		"os":   {runtime.GOOS},
		"arch": {runtime.GOARCH},
	}
	for _, pkgInfo := range pluginPkgs {
		qs.Add("p", pkgInfo.String())
	}

	// initiate the build
	resp, err := downloadBuild(qs)
	if err != nil {
		return caddy.ExitCodeFailedStartup, fmt.Errorf("download failed: %v", err)
	}
	defer resp.Body.Close()

	// back up the current binary, in case something goes wrong we can replace it
	backupExecPath := thisExecPath + ".tmp"
	l.Info("build acquired; backing up current executable",
		zap.String("current_path", thisExecPath),
		zap.String("backup_path", backupExecPath))
	err = os.Rename(thisExecPath, backupExecPath)
	if err != nil {
		return caddy.ExitCodeFailedStartup, fmt.Errorf("backing up current binary: %v", err)
	}
	defer func() {
		if err != nil {
			err2 := os.Rename(backupExecPath, thisExecPath)
			if err2 != nil {
				l.Error("restoring original executable failed; will need to be restored manually",
					zap.String("backup_path", backupExecPath),

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Read the nested error: 'secure request failed' indicates a network/TLS problem; 'HTTP 4xx/5xx ... message' indicates a bad request — fix the module path/version it names
  2. Check connectivity: `curl -I 'https://caddyserver.com/api/download?os=linux&arch=amd64'`; fix DNS, egress rules, or proxy env (HTTPS_PROXY) as needed
  3. For private/unpublishable modules or offline hosts, build locally with xcaddy instead of the download API
  4. Verify the exact module path and a published version tag exist on the Go module proxy (proxy.golang.org)

Example fix

# before (offline / private module)
caddy add-package github.com/corp/private-plugin  # download failed: HTTP 400

# after
xcaddy build --with github.com/corp/private-plugin
Defensive patterns

Strategy: retry

Validate before calling

curl -fsSI --max-time 10 'https://caddyserver.com/api/download?os=linux&arch=amd64' >/dev/null \
  && echo 'download API reachable' \
  || echo 'API unreachable; fix network or use xcaddy build --with <module>'

Try / catch

# shell: run upgrade, fall back to xcaddy on network failure
if ! caddy upgrade; then
  echo 'in-place upgrade failed; falling back to xcaddy' >&2
  xcaddy build --with github.com/caddy-dns/cloudflare
fi

Prevention

When it happens

Trigger: `caddy upgrade`, `caddy add-package`, or `caddy remove-package` with no route to caddyserver.com (offline host, blocked egress, DNS failure, TLS-intercepting proxy); or requesting a module/version the API cannot resolve (typo, yanked version, private repo).

Common situations: Hardened servers and air-gapped environments where the build API is unreachable; corporate proxies whose MITM certificate chain Caddy doesn't trust; adding a plugin from a private repository; caddyserver.com being down or rate-limiting.

Related errors


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