Repository: electron-userland/electron-builder
File: packages/electron-updater/src/AppUpdater.ts (TypeScript)

Code before:
          this.dispatchError(e)
        } catch (nestedError: any) {
          this._logger.warn(`Cannot dispatch error event: ${nestedError.stack || nestedError}`)
        }
      }

      return e
    }

    try {
      this.downloadPromise = this.doDownloadUpdate({
        updateInfoAndProvider,
        requestHeaders: this.computeRequestHeaders(updateInfoAndProvider.provider),
        cancellationToken,
        disableWebInstaller: this.disableWebInstaller,
        disableDifferentialDownload: this.disableDifferentialDownload,
      })
        .catch((e: any) => {
          throw errorHandler(e)
        })
        .finally(() => {
          this.downloadPromise = null
        })
      return this.downloadPromise
    } catch (e: any) {
      return Promise.reject(errorHandler(e))
    }
  }

  protected dispatchError(e: Error): void {
    this.emit("error", e, (e.stack || e).toString())
  }

  protected dispatchUpdateDownloaded(event: UpdateDownloadedEvent): void {
    this.emit(UPDATE_DOWNLOADED, event)
  }

  protected abstract doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise<Array<string>>

  /**
   * Restarts the app and installs the update after it has been downloaded.
   * It should only be called after `update-downloaded` has been emitted.
   *
   * **Note:** `autoUpdater.quitAndInstall()` will close all application windows first and only emit `before-quit` event on `app` after that.
   * This is different from the normal quit event sequence.
   *
   * @param isSilent *windows-only* Runs the installer in silent mode. Defaults to `false`.
   * @param isForceRunAfter Run the app after finish even on silent install. Not applicable for macOS.
   * Ignored if `isSilent` is set to `false`(In this case you can still set `autoRunAppAfterInstall` to `false` to prevent run the app after finish).
   */
  abstract quitAndInstall(isSilent?: boolean, isForceRunAfter?: boolean): void

Review comment (bug):
I think we need to add `this.downloadPromise = null` before this `return` as well as a failsafe.

Code after:
          this.dispatchError(e)
        } catch (nestedError: any) {
          this._logger.warn(`Cannot dispatch error event: ${nestedError.stack || nestedError}`)
        }
      }

      return e
    }

    this.downloadPromise = this.doDownloadUpdate({
      updateInfoAndProvider,
      requestHeaders: this.computeRequestHeaders(updateInfoAndProvider.provider),
      cancellationToken,
      disableWebInstaller: this.disableWebInstaller,
      disableDifferentialDownload: this.disableDifferentialDownload,
    })
      .catch((e: any) => {
        throw errorHandler(e)
      })
      .finally(() => {
        this.downloadPromise = null
      })

    return this.downloadPromise
  }

  protected dispatchError(e: Error): void {
    this.emit("error", e, (e.stack || e).toString())
  }

  protected dispatchUpdateDownloaded(event: UpdateDownloadedEvent): void {
    this.emit(UPDATE_DOWNLOADED, event)
  }

  protected abstract doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise<Array<string>>

  /**
   * Restarts the app and installs the update after it has been downloaded.
   * It should only be called after `update-downloaded` has been emitted.
   *
   * **Note:** `autoUpdater.quitAndInstall()` will close all application windows first and only emit `before-quit` event on `app` after that.
   * This is different from the normal quit event sequence.
   *
   * @param isSilent *windows-only* Runs the installer in silent mode. Defaults to `false`.
   * @param isForceRunAfter Run the app after finish even on silent install. Not applicable for macOS.
   * Ignored if `isSilent` is set to `false`(In this case you can still set `autoRunAppAfterInstall` to `false` to prevent run the app after finish).
   */
  abstract quitAndInstall(isSilent?: boolean, isForceRunAfter?: boolean): void

  private async loadUpdateConfig(): Promise<any> {
    if (this._appUpdateConfigPath == null) {