matryer/xbar · warning

remove previous

Error message

remove previous

What it means

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.

Source

Thrown at pkg/update/update.go:228

		return errors.Wrap(err, "find app path")
	}
	appPathDir := filepath.Dir(appPath)
	appPreviousPath := appPath + ".previous"
	err = os.Rename(appPath, appPreviousPath)
	if err != nil {
		_, statErr := os.Stat(appPath)
		// not exist is ok, just ignore it
		if !os.IsNotExist(statErr) {
			return errors.Wrap(err, "rename existing app")
		}
	}
	err = archiver.Unarchive(f.Name(), appPathDir)
	if err != nil {
		return errors.Wrap(err, "unarchive")
	}
	err = os.RemoveAll(appPreviousPath)
	if err != nil {
		return errors.Wrap(err, "remove previous")
	}
	return nil
}

// Release is a GitHub release.
type Release struct {
	TagName         string    `json:"tag_name"`
	Assets          []Asset   `json:"assets"`
	Body            string    `json:"body"`
	CreatedAtString string    `json:"created_at"`
	CreatedAt       time.Time `json:"created_at_time"`
}

// Asset is a file within a Release on GitHub.
type Asset struct {
	Name               string `json:"name"`
	BrowserDownloadURL string `json:"browser_download_url"`
}

View on GitHub (pinned to d624239058)

Solutions

  1. Manually delete the '<appPath>.previous' file once no process holds it — the update is already applied.
  2. Retry the update; leftover .previous files don't affect the running version.
  3. Ensure antivirus/backup tools exclude the app directory so cleanup files can be removed.
  4. Treat this as a warning-level cleanup issue and log instead of failing the update flow.

Example fix

// before
err = os.RemoveAll(appPreviousPath)
if err != nil {
	return errors.Wrap(err, "remove previous")
}
// after
if err := os.RemoveAll(appPreviousPath); err != nil {
	log.Printf("warning: cleanup of %s failed: %v", appPreviousPath, err)
}
Defensive patterns

Strategy: fallback

Validate before calling

prev := appPath + ".previous"
if _, err := os.Stat(prev); err == nil {
	if err := os.Remove(prev); err != nil {
		log.Printf("previous backup still locked, cleanup deferred: %v", err)
	}
}

Try / catch

err := u.Update()
if err != nil && strings.Contains(err.Error(), "remove previous") {
	log.Printf("update applied but backup cleanup failed; safe to ignore/delete %s.previous: %v", appPath, err)
	return nil
}

Prevention

When it happens

Trigger: Calling Update() when the .previous file cannot be deleted — locked by another process (Windows/AV), read-only, or permission denied in the app directory.

Common situations: 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.

Related errors


AI-assisted analysis of matryer/xbar@d624239058 (2026-09-02). Data as JSON: /api/errors/4ae1690de1d02e15. Report an issue: GitHub.