{"record":{"id":"b67206c380472078","repo":"aaif-goose/goose","slug":"update-file-path-not-found-please-download-the-up","errorCode":null,"errorMessage":"Update file path not found. Please download the update first.","messagePattern":"Update file path not found\\. Please download the update first\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ui/desktop/src/utils/autoUpdater.ts","lineNumber":283,"sourceCode":"      trackUpdateDownloadCompleted(false, version, method, errorMessage(error, 'unknown'));\n      return {\n        success: false,\n        error: errorMessage(error, 'Unknown error'),\n      };\n    }\n  });\n\n  ipcMain.handle('install-update', async () => {\n    if (isUsingGitHubFallback) {\n      // For GitHub fallback, we need to handle the installation differently\n      log.info('Installing update from GitHub fallback...');\n\n      try {\n        // Use the stored extracted path if available, otherwise download path\n        const updatePath = githubUpdateInfo.extractedPath || githubUpdateInfo.downloadPath;\n\n        if (!updatePath) {\n          throw new Error('Update file path not found. Please download the update first.');\n        }\n\n        // Check if the update path exists\n        try {\n          await fs.access(updatePath);\n        } catch {\n          throw new Error('Update file not found. Please download the update first.');\n        }\n\n        // Improved dialog with clearer instructions\n        const dialogResult = (await dialog.showMessageBox({\n          type: 'info',\n          title: 'Update Ready to Install',\n          message: `Version ${githubUpdateInfo.latestVersion} is ready to install.`,\n          detail: `The update has been downloaded and extracted. To complete the installation:\\n\\n1. Click \"Open Folder\" to view the new Goose.app\\n2. Quit Goose (this app will close)\\n3. Drag the new Goose.app to your Applications folder\\n4. Replace the existing app when prompted\\n\\nThe update will be available the next time you launch Goose.`,\n          buttons: ['Open Folder & Quit', 'Open Folder Only', 'Cancel'],\n          defaultId: 0,\n          cancelId: 2,","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/ui/desktop/src/utils/autoUpdater.ts#L265-L301","documentation":"In the GitHub-fallback update path (electron-updater failed, release info came from the GitHub API), 'install-update' needs a local path: either githubUpdateInfo.extractedPath (post-extract) or downloadPath. If both are unset the handler throws this — meaning install was invoked before a download ever completed or after state was reset by a new update check (which clears githubUpdateInfo).","triggerScenarios":"Renderer invokes install-update right after check-for-updates reported an update but before download-update finished; a second check-for-updates ran in between and reset githubUpdateInfo = {}; failed download that never stored downloadPath.","commonSituations":"UI state machine bugs that enable the Install button before download completes; user retrying install after a failed download without re-downloading; race between auto-check and manual install.","solutions":["Run the download step to completion first, then invoke install-update","Avoid triggering another check-for-updates between download and install — it wipes the stored paths","If state is already lost, start over: check for updates, download, then install","UI: disable the install action until a download-success event is observed"],"exampleFix":"// renderer: before (install enabled after check only)\nconst info = await api.checkForUpdates();\nif (info.updateInfo) enableInstall();\n// after (require completed download)\nconst info = await api.checkForUpdates();\nawait api.downloadUpdate(); // sets downloadPath/extractedPath\nenableInstall();","handlingStrategy":"validation","validationCode":"// Renderer: only enable install after download completes\nconst res = await api.downloadUpdate();\nif (res?.success) enableInstallButton(); // downloadPath/extractedPath now set","typeGuard":"const hasDownloadedUpdate = (): boolean =>\n  Boolean(githubUpdateInfo.extractedPath || githubUpdateInfo.downloadPath); // module-internal","tryCatchPattern":"try {\n  await window.api.installUpdate();\n} catch (e) {\n  if (String(e).includes('path not found')) {\n    // re-run check-for-updates -> download-update -> install, in order\n  }\n}","preventionTips":["Enforce check -> download -> install ordering in the UI state machine","Never trigger check-for-updates while an update is downloaded-but-uninstalled (it resets state)","Persist download path across restarts if install can happen later"],"tags":["auto-update","github-fallback","state-machine","ipc"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}