{"record":{"id":"4ae1690de1d02e15","repo":"matryer/xbar","slug":"remove-previous","errorCode":null,"errorMessage":"remove previous","messagePattern":"remove previous","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/update/update.go","lineNumber":228,"sourceCode":"\t\treturn errors.Wrap(err, \"find app path\")\n\t}\n\tappPathDir := filepath.Dir(appPath)\n\tappPreviousPath := appPath + \".previous\"\n\terr = os.Rename(appPath, appPreviousPath)\n\tif err != nil {\n\t\t_, statErr := os.Stat(appPath)\n\t\t// not exist is ok, just ignore it\n\t\tif !os.IsNotExist(statErr) {\n\t\t\treturn errors.Wrap(err, \"rename existing app\")\n\t\t}\n\t}\n\terr = archiver.Unarchive(f.Name(), appPathDir)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"unarchive\")\n\t}\n\terr = os.RemoveAll(appPreviousPath)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"remove previous\")\n\t}\n\treturn nil\n}\n\n// Release is a GitHub release.\ntype Release struct {\n\tTagName         string    `json:\"tag_name\"`\n\tAssets          []Asset   `json:\"assets\"`\n\tBody            string    `json:\"body\"`\n\tCreatedAtString string    `json:\"created_at\"`\n\tCreatedAt       time.Time `json:\"created_at_time\"`\n}\n\n// Asset is a file within a Release on GitHub.\ntype Asset struct {\n\tName               string `json:\"name\"`\n\tBrowserDownloadURL string `json:\"browser_download_url\"`\n}","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/matryer/xbar/blob/d624239058997c80118eaebe2e7f8331b3c765e0/pkg/update/update.go#L210-L246","documentation":"os.RemoveAll of the '<appPath>.previous' backup failed after the new version was successfully extracted; the error is wrapped as 'remove previous'. The update itself is in place — this is only cleanup of the old binary backup.","triggerScenarios":"Calling Update() when the .previous file cannot be deleted — locked by another process (Windows/AV), read-only, or permission denied in the app directory.","commonSituations":"Antivirus or backup software holding the .previous file; read-only mount; the .previous path is a non-empty directory owned by another user; Windows delayed file release after rename.","solutions":["Manually delete the '<appPath>.previous' file once no process holds it — the update is already applied.","Retry the update; leftover .previous files don't affect the running version.","Ensure antivirus/backup tools exclude the app directory so cleanup files can be removed.","Treat this as a warning-level cleanup issue and log instead of failing the update flow."],"exampleFix":"// before\nerr = os.RemoveAll(appPreviousPath)\nif err != nil {\n\treturn errors.Wrap(err, \"remove previous\")\n}\n// after\nif err := os.RemoveAll(appPreviousPath); err != nil {\n\tlog.Printf(\"warning: cleanup of %s failed: %v\", appPreviousPath, err)\n}","handlingStrategy":"fallback","validationCode":"prev := appPath + \".previous\"\nif _, err := os.Stat(prev); err == nil {\n\tif err := os.Remove(prev); err != nil {\n\t\tlog.Printf(\"previous backup still locked, cleanup deferred: %v\", err)\n\t}\n}","typeGuard":null,"tryCatchPattern":"err := u.Update()\nif err != nil && strings.Contains(err.Error(), \"remove previous\") {\n\tlog.Printf(\"update applied but backup cleanup failed; safe to ignore/delete %s.previous: %v\", appPath, err)\n\treturn nil\n}","preventionTips":["Exclude the install dir from antivirus/backup locking","Clean stale .previous files on the next app startup","Log-and-continue for post-success cleanup failures instead of failing the update"],"tags":["filesystem","cleanup","permissions"],"backgroundTag":"file-delete-failed","analyzedSha":"d624239058997c80118eaebe2e7f8331b3c765e0","analyzedAt":"2026-09-02T22:38:22.007Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}