caddyserver/caddy · warning
download succeeded, but unable to clean up backup binary
Error message
download succeeded, but unable to clean up backup binary: %v
What it means
The upgrade itself fully succeeded (downloaded, verified, executed), but removing the backup file '<exec>.tmp' failed because --keep-backup was not set. Despite the message prefix, the new binary is in place and working; only the leftover backup is the issue. Note the deferred restore does NOT run because err is set, so the .tmp file is intentionally left for manual cleanup.
Solutions
- Verify the new binary works: caddy version — the upgrade itself succeeded
- Delete the leftover backup with appropriate privileges: sudo rm -f /path/to/caddy.tmp
- Pass --keep-backup on future upgrades if you want the backup retained deliberately
- Fix ownership of the binary directory so future runs can clean up: sudo chown $(id -u) <dir>
Example fix
# before caddy upgrade # error: download succeeded, but unable to clean up backup binary: remove /usr/local/bin/caddy.tmp: permission denied # after sudo rm -f /usr/local/bin/caddy.tmp caddy version # confirm upgrade took effect
Defensive patterns
Strategy: validation
Validate before calling
caddy version # confirm upgrade landed ls -l "$(command -v caddy).tmp" 2>/dev/null && sudo rm -f "$(command -v caddy).tmp"
Prevention
- Pass --keep-backup when you want the rollback copy preserved intentionally
- Keep ownership of the binary directory consistent (always upgrade with the same privileges)
When it happens
Trigger: os.Remove failing on the backup: file owned by a different user (e.g. upgrade run with sudo but .tmp owned by root from a previous run), read-only directory, or the file held open by another process.
Common situations: Mixed privileged/unprivileged upgrades leaving root-owned .tmp files; a leftover caddy.tmp held open by a crashed process.
Related errors
- backing up current binary
- checking if default Caddyfile exists
- download failed
- download succeeded, but unable to execute 'caddy…
- download succeeded, but unable to execute 'caddy version
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/416a2843bb359ad7.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/packagesfuncs.go:205
}
l.Info("download successful; displaying new binary details", zap.String("location", thisExecPath))
// use the new binary to print out version and module info
fmt.Print("\nModule versions:\n\n")
if err = listModules(thisExecPath); err != nil {
return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to execute 'caddy list-modules': %v", err)
}
fmt.Println("\nVersion:")
if err = showVersion(thisExecPath); err != nil {
return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to execute 'caddy version': %v", err)
}
fmt.Println()
// clean up the backup file
if !fl.Bool("keep-backup") {
if err = removeCaddyBinary(backupExecPath); err != nil {
return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to clean up backup binary: %v", err)
}
} else {
l.Info("skipped cleaning up the backup file", zap.String("backup_path", backupExecPath))
}
l.Info("upgrade successful; please restart any running Caddy instances", zap.String("executable", thisExecPath))
return caddy.ExitCodeSuccess, nil
}
func getModules() (standard, nonstandard, unknown []moduleInfo, err error) {
bi, ok := debug.ReadBuildInfo()
if !ok {
err = fmt.Errorf("no build info")
return standard, nonstandard, unknown, err
}
for _, modID := range caddy.Modules() {View on GitHub (pinned to 50e54ee279)