matryer/xbar · error

unarchive

Error message

unarchive

What it means

Raised in Updater.downloadAndReplaceApp when archiver.Unarchive fails to extract the downloaded update archive into the app's directory. By this point the running app has already been renamed to the '.previous' path, so a failure here leaves the installation in a swapped-out state: the old build exists only under appPath + '.previous' and the update is not applied.

Source

Thrown at pkg/update/update.go:224

		return errors.Wrap(err, "get executable")
	}
	appPath, err := appPathFromExecutable(executable)
	if err != nil {
		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.

View on GitHub (pinned to d624239058)

Solutions

  1. Verify the downloaded archive is complete and not corrupted (check size/hash before unarchiving)
  2. Confirm the archive format is one the archiver library supports
  3. Check write permissions and free disk space in appPathDir
  4. On failure, restore the app by renaming the '.previous' copy back to appPath so the old version still runs
  5. Re-download the archive if it was truncated or tampered with
Defensive patterns

Strategy: fallback

Validate before calling

zr, err := zip.OpenReader(downloadedZipPath)
if err != nil {
	return fmt.Errorf("downloaded asset is not a valid zip: %w", err)
}
zr.Close()

Try / catch

err := u.Update()
if err != nil && strings.Contains(err.Error(), "unarchive") {
	log.Printf("update archive invalid; re-downloading: %v", err)
	return retryUpdate()
}

Prevention

When it happens

Trigger: Calling Update() when the downloaded asset is a corrupt/truncated zip, is not actually a zip despite the extension, contains files with paths the extractor can't write (permissions, existing locked files), or the zip uses unsupported compression/encryption.

Common situations: Download interrupted earlier producing a partial zip; server returned an HTML error page saved with a .zip name; extracting over files locked by running processes on Windows; zips created with encryption or non-deflate compression.

Related errors


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