Skip to content

autoUpdater.quitAndInstall() fails to apply update and app does not relaunch #50200

@nikwen

Description

@nikwen

Preflight Checklist

Electron Version

39.6.0

What operating system(s) are you using?

macOS

Operating System Version

Unsure (not my machine)

What arch are you using?

arm64 (including Apple Silicon)

Last Known Working Electron version

No response

Does the issue also appear in Chromium / Google Chrome?

No

Expected Behavior

After 'update-downloaded', calling autoUpdater.quitAndInstall() will apply the update and restart the app.

Actual Behavior

I have privately received a report that autoUpdater.quitAndInstall() no longer consistently applies updates and restarts the app in a very popular Electron application on macOS.

The new version is downloaded, but on autoUpdater.quitAndInstall() the app never relaunches.

This started happening after upgrading to Electron 39.6.0. It does not happen on every update, but it happens often enough to be a problem.

When the issue occurs, the following logs are printed:

2026-03-07 14:15:48.938 ShipIt[91919:9806597] Installation error: Error Domain=SQRLInstallerErrorDomain Code=-1 "Failed to copy bundle file:///Users/name/Library/Caches/com.appname.ShipIt/update.0vPlgMV/Name.app/ to directory file:///var/folders/xr/4nvbvbf97td72pr6qh1mm4p00000gn/T/com.appname.ShipIt.QHGrIddV/Name.app" UserInfo={NSLocalizedDescription=Failed to copy bundle file:///Users/name/Library/Caches/com.appname.ShipIt/update.0vPlgMV/Name.app/ to directory file:///var/folders/xr/4nvbvbf97td72pr6qh1mm4p00000gn/T/com.appname.ShipIt.QHGrIddV/Name.app, NSFilePath=/Users/name/Library/Caches/com.appname.ShipIt/update.0vPlgMV/Name.app, NSURL=file:///Users/name/Library/Caches/com.appname.ShipIt/update.0vPlgMV/Name.app, NSUnderlyingError=0x95b014600 {Error Domain=NSCocoaErrorDomain Code=260 "The file "Name.app" couldn't be opened because there is no such file." UserInfo={NSFilePath=/Users/name/Library/Caches/com.appname.ShipIt/update.0vPlgMV/Name.app, NSURL=file:///Users/name/Library/Caches/com.appname.ShipIt/update.0vPlgMV/Name.app, NSUnderlyingError=0x95b0145a0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}}}
2026-03-07 14:15:48.938 ShipIt[91919:9806597] ShipIt quitting
2026-03-07 14:15:51.005 ShipIt[91926:9806656] Detected this as an install request
2026-03-07 14:15:51.020 ShipIt[91926:9806656] Too many attempts to install, aborting update
2026-03-07 14:15:51.021 ShipIt[91926:9806656] ShipIt quitting

The important part is:

The file "Name.app" couldn't be opened because there is no such file.

Testcase Gist URL

No response

Additional Information

This seems like a consequence of #49365, backported to Electron 39.6.0.

That PR introduced logic to remove previously downloaded updates when autoUpdater.checkForUpdates() is called.

It's easy to imagine a race condition such as the following:

  1. autoUpdater.checkForUpdates() is called
  2. An update is downloaded
  3. The download finishes
  4. The user is shown a UI element with the option to install the update
  5. autoUpdater.checkForUpdates() is called again (e.g., periodically in a setInterval())
  6. This deletes the directory of the previously downloaded update
  7. It starts downloading the new version
  8. However, the path of the previously downloaded update is still referenced in ShipItState.plist
  9. The user clicks on "Update & Restart" in the UI before the new download is complete
  10. autoUpdater.quitAndInstall() is called
  11. It reads the path of the previously downloaded update from ShipItState.plist and tries to install it
  12. The update fails because the directory no longer exists (inside of prepareAndValidateUpdateBundleURLForRequest, link 1, link 2)
  13. The app does not relaunch

This race condition is also not as rare as it might seem. Electron apps can easily reach 500MB or more. On a slow connection, that download can take a few minutes. If the user decides to update at any point during those few minutes, this bug will occur.

IMPORTANT: It is not safe to delete old ShipIt directories! They might still be referenced by ShipItState.plist or a download to those directories might be in progress and they will be referenced by ShipItState.plist once that download completes. Deleting them leaves us with a broken Squirrel.Mac state!

Another problem is that #49365 was a feature labeled as a bug fix and was thus backported to older release branches without WG Releases approval in violation of our normal processes. We have to be very careful with the auto updater, and I'm fairly certain these backports would not have been approved had they been properly marked as a feature.

Metadata

Metadata

Type

Projects

Status

🛠️ Fixed for Next Release

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions