Skip to content

Update install leaves the app running with a retired Runtime Host, and never applies the update #5539

Description

@MasamiYui

What happened

Installing a Desktop update never completes. The app keeps running with its Runtime Host already retired, so every Host-backed IPC channel fails and the UI empties out: the Projects list renders "No project" and refreshing model connections reports a network error. The error is misleading — nothing is wrong with the network.

The update itself is never applied. /Applications/Maka.app stays on the previous version, so the next launch offers the same update and fails the same way. The only way out is to quit and relaunch manually.

This reproduces on every install attempt on this machine.

Expected: the app quits, Squirrel replaces the bundle, and the app relaunches on the new version.

How to reproduce

  1. Run a packaged nightly build (observed on 0.2.0-dev.39.20260916).
  2. Let the updater find a newer nightly, or trigger a check from Settings → About.
  3. Click install once the update is downloaded and verified.
  4. The window stays open. Within ~15s the Projects list shows "No project" and a "刷新模型连接失败 / 网络错误" toast appears.
  5. The process never exits. ~/Library/Caches/com.maka.desktop.ShipIt/ShipIt_stderr.log shows ShipIt waiting for it.
  6. Quit manually and relaunch. The app works again, but the bundle is still the old version.

Environment

  • Maka version: 0.2.0-dev.39.20260916 (packaged, nightly channel)
  • OS: macOS 25.6.0 (darwin, arm64)
  • Surface: Desktop
  • Electron 43.4.1 / Chrome 150.0.7871.224 / Node 24.18.1

Logs, screenshots, or additional context

ShipIt, showing it wait ten minutes for a process that never exits, then abort because the app came back (local time):

2026-09-20 10:43:28.878 ShipIt[23809] Detected this as an install request
2026-09-20 10:53:37.123 ShipIt[23809] Beginning installation
2026-09-20 10:54:01.154 ShipIt[23809] Aborting update attempt because there are 1 running instances of the target app
2026-09-20 10:54:01.154 ShipIt[23809] Installation cancelled: Error Domain=SQRLInstallerErrorDomain Code=-9 "App Still Running Error"

The same failure occurred on an earlier attempt that day (10:03:15 → 10:03:58), which is why it reads as always reproducible rather than a race.

Desktop diagnostic report from the same run (UTC, +8h offset from the log above). The Host exits cleanly at 10:43:23 local, and the first IPC failure lands exactly 15s later — DEFAULT_REPLACEMENT_WAIT_TIMEOUT_MS:

[2026-09-20T02:43:23.914Z] INFO [runtime-host] candidate exited cleanly { pid: 68872, code: 0, signal: null }
[2026-09-20T02:43:38.857Z] ERROR Error occurred in handler for 'skills:listInvocable': RuntimeHostHandlerUnavailableError
[2026-09-20T02:50:48.218Z] ERROR Error occurred in handler for 'projects:getSnapshot': RuntimeHostHandlerUnavailableError
[2026-09-20T02:50:48.200Z] ERROR Error occurred in handler for 'connections:getSnapshot': RuntimeHostHandlerUnavailableError

Runtime Host connections (1)
"local": reconnecting
Main process uptime: 2856s

Two details narrow it down:

  • The report was captured at 02:51 UTC with uptime 2856s, i.e. the process started at 02:03 and never restarted. The window was still visible, so prepareToQuit() never reached its browserWindow().destroy().
  • There is not a single [runtime-host] reconnecting: line after the Host exits. The reconnect lifecycle was quiesced by the retirement and never rescheduled, which is why the state stays reconnecting forever without producing an error.

Root cause

installUpdate retires the Host (quiesce() + candidateLaunchBarrier.pause()) before calling quitAndInstall, and that retirement only unwinds through the rollback stored in installHandoff. The quit that was supposed to follow never finishes, because prepareToQuit() and cleanup() are awaited without any upper bound. Once a stage stops settling, phase stays in preparing/cleaning and every later quit request is swallowed by if (phase !== 'running') return after the event was already prevented.

Squirrel's ShipIt is an independent process that only waits for the target to exit, so a quit that never finishes blocks the install indefinitely with nothing to read. The App Still Running Error at the end is a consequence, not the cause: by the time the user gives up and relaunches, ShipIt has finally started installing and finds the app running again.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions