{"record":{"id":"1fbe3eda819ae97d","repo":"gitbutlerapp/gitbutler","slug":"download-function-not-available","errorCode":null,"errorMessage":"Download function not available.","messagePattern":"Download function not available\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/src/lib/updater/updater.ts","lineNumber":160,"sourceCode":"\tasync downloadAndInstall() {\n\t\tthis.loading.set(true);\n\t\ttry {\n\t\t\tawait this.download();\n\t\t\tawait this.install();\n\t\t\tthis.posthog.capture(\"App Update Successful\");\n\t\t} catch (error: any) {\n\t\t\t// We expect toast to be shown by error handling in `onUpdaterEvent`\n\t\t\thandleError(error, true);\n\t\t\tthis.update.set({ status: \"Error\" });\n\t\t\tthis.posthog.capture(\"App Update Install Error\", { error });\n\t\t} finally {\n\t\t\tthis.loading.set(false);\n\t\t}\n\t}\n\n\tprivate async download() {\n\t\tif (!this.backendDownload) {\n\t\t\tthrow new Error(\"Download function not available.\");\n\t\t}\n\t\tthis.setStatus(\"Downloading\");\n\t\tawait this.backendDownload((progress: DownloadEvent) => {\n\t\t\tthis.setStatus(downloadStatusMap[progress.event]);\n\t\t});\n\t\tthis.setStatus(\"Downloaded\");\n\t}\n\n\tprivate async install() {\n\t\tif (!this.backendInstall) {\n\t\t\tthrow new Error(\"Install function not available.\");\n\t\t}\n\t\tthis.setStatus(\"Installing\");\n\t\tawait this.backendInstall();\n\t\tthis.setStatus(\"Done\");\n\t}\n\n\tprivate setStatus(status: InstallStatus) {","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/apps/desktop/src/lib/updater/updater.ts#L142-L178","documentation":"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.","triggerScenarios":"Calling downloadAndInstall() (which calls download()) when backendDownload was never set — no pending update, updater unavailable (dev build, unsupported platform, or tauri updater plugin disabled).","commonSituations":"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.","solutions":["Only call downloadAndInstall after a successful update check that confirmed an update is available.","Guard the UI update button with the updater's availability/status state.","Verify the Tauri updater plugin is configured and the app is a packaged build (not dev mode)."],"exampleFix":"// before\nawait updater.downloadAndInstall();\n// after\nif (await updater.check()) {\n  await updater.downloadAndInstall();\n}","handlingStrategy":"validation","validationCode":"if (!updater.isUpdateAvailable()) return;\nawait updater.downloadAndInstall();","typeGuard":null,"tryCatchPattern":"try {\n  await updater.downloadAndInstall();\n} catch (e) {\n  showToast('Auto-update unavailable in this build');\n}","preventionTips":["Only expose update actions after a successful check()","Track updater availability in app state and gate the UI","Remember dev builds and unsupported platforms have no updater"],"tags":["updater","initialization","desktop"],"backgroundTag":"feature-not-enabled","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}