gitbutlerapp/gitbutler · error

Download function not available.

Error message

Download function not available.

What it means

Thrown by the updater's private download() when this.backendDownload is unset. The backend download function is only assigned when the updater/tauri plugin reports availability (e.g. update check succeeded on a supported platform). Attempting to download without it means the updater was never initialized with a downloadable update.

Solutions

  1. Only call downloadAndInstall after a successful update check that confirmed an update is available.
  2. Guard the UI update button with the updater's availability/status state.
  3. Verify the Tauri updater plugin is configured and the app is a packaged build (not dev mode).

Example fix

// before
await updater.downloadAndInstall();
// after
if (await updater.check()) {
  await updater.downloadAndInstall();
}
Defensive patterns

Strategy: validation

Validate before calling

if (!updater.isUpdateAvailable()) return;
await updater.downloadAndInstall();

Try / catch

try {
  await updater.downloadAndInstall();
} catch (e) {
  showToast('Auto-update unavailable in this build');
}

Prevention

When it happens

Trigger: Calling downloadAndInstall() (which calls download()) when backendDownload was never set — no pending update, updater unavailable (dev build, unsupported platform, or tauri updater plugin disabled).

Common situations: Running in development where auto-update is disabled; calling downloadAndInstall without a prior successful check() that registered the backend functions; Linux builds where the updater isn't supported.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/1fbe3eda819ae97d. Report an issue: GitHub.

Appendix: source

Thrown at apps/desktop/src/lib/updater/updater.ts:160

	async downloadAndInstall() {
		this.loading.set(true);
		try {
			await this.download();
			await this.install();
			this.posthog.capture("App Update Successful");
		} catch (error: any) {
			// We expect toast to be shown by error handling in `onUpdaterEvent`
			handleError(error, true);
			this.update.set({ status: "Error" });
			this.posthog.capture("App Update Install Error", { error });
		} finally {
			this.loading.set(false);
		}
	}

	private async download() {
		if (!this.backendDownload) {
			throw new Error("Download function not available.");
		}
		this.setStatus("Downloading");
		await this.backendDownload((progress: DownloadEvent) => {
			this.setStatus(downloadStatusMap[progress.event]);
		});
		this.setStatus("Downloaded");
	}

	private async install() {
		if (!this.backendInstall) {
			throw new Error("Install function not available.");
		}
		this.setStatus("Installing");
		await this.backendInstall();
		this.setStatus("Done");
	}

	private setStatus(status: InstallStatus) {

View on GitHub (pinned to 58e5313667)