{"record":{"id":"416a2843bb359ad7","repo":"caddyserver/caddy","slug":"download-succeeded-but-unable-to-clean-up-backup","errorCode":null,"errorMessage":"download succeeded, but unable to clean up backup binary: %v","messagePattern":"download succeeded, but unable to clean up backup binary: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/packagesfuncs.go","lineNumber":205,"sourceCode":"\t}\n\n\tl.Info(\"download successful; displaying new binary details\", zap.String(\"location\", thisExecPath))\n\n\t// use the new binary to print out version and module info\n\tfmt.Print(\"\\nModule versions:\\n\\n\")\n\tif err = listModules(thisExecPath); err != nil {\n\t\treturn caddy.ExitCodeFailedStartup, fmt.Errorf(\"download succeeded, but unable to execute 'caddy list-modules': %v\", err)\n\t}\n\tfmt.Println(\"\\nVersion:\")\n\tif err = showVersion(thisExecPath); err != nil {\n\t\treturn caddy.ExitCodeFailedStartup, fmt.Errorf(\"download succeeded, but unable to execute 'caddy version': %v\", err)\n\t}\n\tfmt.Println()\n\n\t// clean up the backup file\n\tif !fl.Bool(\"keep-backup\") {\n\t\tif err = removeCaddyBinary(backupExecPath); err != nil {\n\t\t\treturn caddy.ExitCodeFailedStartup, fmt.Errorf(\"download succeeded, but unable to clean up backup binary: %v\", err)\n\t\t}\n\t} else {\n\t\tl.Info(\"skipped cleaning up the backup file\", zap.String(\"backup_path\", backupExecPath))\n\t}\n\n\tl.Info(\"upgrade successful; please restart any running Caddy instances\", zap.String(\"executable\", thisExecPath))\n\n\treturn caddy.ExitCodeSuccess, nil\n}\n\nfunc getModules() (standard, nonstandard, unknown []moduleInfo, err error) {\n\tbi, ok := debug.ReadBuildInfo()\n\tif !ok {\n\t\terr = fmt.Errorf(\"no build info\")\n\t\treturn standard, nonstandard, unknown, err\n\t}\n\n\tfor _, modID := range caddy.Modules() {","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/cmd/packagesfuncs.go#L187-L223","documentation":"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.","triggerScenarios":"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.","commonSituations":"Mixed privileged/unprivileged upgrades leaving root-owned .tmp files; a leftover caddy.tmp held open by a crashed process.","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>"],"exampleFix":"# before\ncaddy upgrade\n# error: download succeeded, but unable to clean up backup binary: remove /usr/local/bin/caddy.tmp: permission denied\n\n# after\nsudo rm -f /usr/local/bin/caddy.tmp\ncaddy version  # confirm upgrade took effect","handlingStrategy":"validation","validationCode":"caddy version                      # confirm upgrade landed\nls -l \"$(command -v caddy).tmp\" 2>/dev/null && sudo rm -f \"$(command -v caddy).tmp\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass --keep-backup when you want the rollback copy preserved intentionally","Keep ownership of the binary directory consistent (always upgrade with the same privileges)"],"tags":["upgrade","cleanup","permissions","cli"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}