caddyserver/caddy · error
backing up current binary: %v
Error message
backing up current binary: %v
What it means
Thrown by caddy upgrade/add-package after a custom build has been downloaded from caddyserver.com, when os.Rename fails while moving the current executable to '<exec>.tmp' before overwriting it. The upgrade aborts before anything is modified, so the original binary is untouched. The underlying cause is almost always filesystem permissions or the executable being locked by a running process.
Source
Thrown at cmd/packagesfuncs.go:169
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),
zap.String("original_path", thisExecPath),
zap.Error(err2))
}
}
}()
// download the file; do this in a closure to close reliably before we execute it
err = writeCaddyBinary(thisExecPath, &resp.Body, thisExecStat)
if err != nil {
return caddy.ExitCodeFailedStartup, err
}View on GitHub (pinned to 50e54ee279)
Solutions
- Re-run with sufficient privileges: 'sudo caddy upgrade' (Linux/macOS) or an elevated shell on Windows
- Stop all running Caddy instances before upgrading (on Windows the exe is locked while running)
- Verify write permission on the binary's directory: ls -ld $(dirname $(which caddy)); chmod or chown if needed
- Remove a stale read-only backup: rm -f $(which caddy).tmp
- If on a read-only filesystem, copy the binary to a writable location, upgrade there, then move it back
Example fix
# before caddy upgrade # error: backinging up current binary: rename /usr/local/bin/caddy /usr/local/bin/caddy.tmp: permission denied # after sudo caddy upgrade
Defensive patterns
Strategy: validation
Validate before calling
# before running caddy upgrade
EXEC="$(command -v caddy)"
DIR="$(dirname "$EXEC")"
[ -w "$DIR" ] || { echo "not writable: $DIR (use sudo)"; exit 1; }
[ -f "$EXEC.tmp" ] && rm -f "$EXEC.tmp"
df -h "$DIR" | tail -1 # confirm space
# on Windows: stop the caddy service first (sc stop caddy) Prevention
- Always stop running Caddy instances before 'caddy upgrade' (mandatory on Windows where the exe is locked)
- Run upgrade with the privileges that own the binary's directory
- Keep the caddy binary on writable local storage, never on a read-only mount
- Clear stale .tmp backups before upgrading
When it happens
Trigger: Running 'caddy upgrade' or 'caddy add-package' when: the directory containing the binary is not writable by the current user (e.g. /usr/bin owned by root and running unprivileged); on Windows, a caddy instance is still running so the exe file is locked; a stale '<exec>.tmp' exists as read-only; the filesystem is read-only (container, mounted volume).
Common situations: Installing caddy via a package manager into /usr/bin or /usr/local/bin and running 'caddy upgrade' without sudo; forgetting to stop systemd caddy service on Windows; running inside a Docker container where the binary lives on a read-only layer.
Related errors
- checking if default Caddyfile exists: %v
- reading default Caddyfile: %v
- retrieving current executable permission bits: %v
- resolving current executable symlink: %v
- download succeeded, but unable to clean up backup binary: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/8e3e5760c35ffd52.
Report an issue: GitHub.