You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Windows] Desktop update silently fails to apply — installer stages .new-{GUID} sibling dir, swap never completes, badge returns every launch
#8284
Related to #8198, but not the same defect. That report is the macOS loud variant: the in-app update refuses the handoff with desktop update: Host did not complete graceful task teardown (...). This one is the Windows silent variant: the installer really does run and extracts a complete payload, then the directory swap never completes — and nothing is surfaced anywhere, so the only visible symptom is a badge that comes back on every launch.
The in-app update appears to run — the installer executes and the app relaunches — but the installed version never changes, and no error is shown anywhere. Every launch reports a new version is available, because the update is genuinely still pending.
Evidence: two attempts, nothing applied
Check
Value after two update attempts
HKCU\...\Uninstall\1bf39983-... → DisplayVersion
0.2.0-rc.1
<install>\DeepSeek Harness.exe → FileVersion
0.2.0-rc.1
<install>\Uninstall DeepSeek Harness.exe
0.2.0-rc.1
resources\app.asar → package.json → version
0.2.0-rc.1
Running process image
<install>\DeepSeek Harness.exe
Two abandoned staging directories were left next to the install (local time, UTC+8):
Both hold a full, self-consistent app tree: resources/app.asar whose package.json reads 0.2.0-rc.2 (dshBuildCommit04f392c9ddd144fa426da2045178797da6db6c11), plus a freshly generated Uninstall DeepSeek Harness.exe stamped 0.2.0-rc.2. So extraction finished; only the swap into the install directory did not happen.
The installer stages deliberately, then fails to swap
The cached installer is intact — SHA-512 matches nightly.yml byte-for-byte (raIlxMQd9ESXgktmViW7QwVLcjBR5JIsrNOu+SpelY8kskdSr2H51/f+ey1EqFI/eIIrKQCuRANMeb5SptRZcg==, 289,313,640 bytes).
The staging path is literally the install directory plus .new-{GUID} — the installer resolved the correct target and deliberately staged a sibling copy of the whole payload. I scanned the packed app.asar (which is uncompressed) for any .new- literal: 0 hits, so this staging is installer-side, not shell-side.
Why the swap fails (measured, not inferred)
While the app is running, the two files the swap must replace are held open:
<install>\DeepSeek Harness.exe -> "The process cannot access the file ... because it is being used by another process."
<install>\resources\app.asar -> "The process cannot access the file ... because it is being used by another process."
<install>.new-{...}\DeepSeek Harness.exe -> writable (nothing is running from it)
Ruled out:
Permissions — creating and deleting a file inside the install directory succeeds.
Disk — 197 GB free on the volume; NTFS, healthy.
Corruption — installer SHA-512 matches the manifest exactly.
A space in the install path — the original install into the same directory succeeded, and the manual re-run below succeeded there too.
Controlled contrast
Same cached installer, same flags as the in-app path (--updated /S), one variable changed: every DeepSeek Harness.exe process stopped and the two files above proven unlocked before launching.
installer exit code : 0 (24 seconds)
installed version : 0.2.0-rc.2 (verified via exe FileVersion, uninstaller, registry, app.asar)
The package, feed, flags and install location are all fine. The only blocker is that the app's own files are still held when the swap runs.
Relationship to #8198 — and why the ack is not sufficient
#8198 identifies a real gate: DesktopHostProcess.stop(requireGraceful = true) refuses the handoff unless the child exited with code 0 and sent a shutdown-complete ack, while the host's PROCESS_SHUTDOWN_TIMEOUT_MS = 5000 force-exits before sending that ack. That gate is unchanged in 0.2.0-rc.2 (shell window is 10 s; host still 5 s).
In the case reported here the gate evidently passed — the NSIS installer was genuinely launched and extracted a complete payload. So a successful shutdown-complete does not imply the install is replaceable. What NSIS needs is for the main Electron process to have released <install>\DeepSeek Harness.exe and <install>\resources\app.asar before it starts replacing them. The current gate verifies the child host's teardown, not the parent's file handles, and not the installer's outcome.
Observability gap
The update journal (DesktopUpdateJournal / lib/types/update-journal.js) is opt-in via DSH_DESKTOP_UPDATE_JOURNAL_DIR. Unset by default, so a stock install records nothing at all.
Its last records for an install are install-confirmed and quit-requested. After quitAndInstall(true, true) the process is gone, so the installer's result has no channel back into the app — even with the journal enabled, this failure is indistinguishable from success.
Its error classification is a fixed whitelist of 8 codes; a swap failure produces no error state and therefore no code.
Suggested fixes (any one would help)
Gate the handoff on the install directory, not only on the host ack. After the host exits, confirm <install>\<exe> and resources\app.asar can be opened for exclusive write — or simply wait for the main process to exit — before spawning the installer.
Make the swap resilient and honest. Retry the replace for N seconds; on failure remove the .new-{GUID} staging directory and record the outcome so the next launch can report it, instead of failing silently.
Detect the stuck state on next launch. If a .new-{GUID} sibling exists while the feed version is still newer than the running version, surface an actionable message ("the previous update did not apply — quit the app fully and run the installer manually") instead of re-offering the same update forever.
Workaround
Quit the desktop app completely — check Task Manager for DeepSeek Harness.exe; tray/background mode keeps processes alive — then run the already-downloaded installer:
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Environment
nightlychannelD:\dsh dp(not the default%LOCALAPPDATA%\Programs\...);resources/app-update.ymlreportsisAdminRightsRequired: falsehttps://download.deepseek.com/dsh-desk/feeds/win-x64/nightly.yml→version: 0.2.0-rc.2,releaseDate: 2026-09-29T10:35:27.666ZSymptom
The in-app update appears to run — the installer executes and the app relaunches — but the installed version never changes, and no error is shown anywhere. Every launch reports a new version is available, because the update is genuinely still pending.
Evidence: two attempts, nothing applied
HKCU\...\Uninstall\1bf39983-...→DisplayVersion0.2.0-rc.1<install>\DeepSeek Harness.exe→FileVersion0.2.0-rc.1<install>\Uninstall DeepSeek Harness.exe0.2.0-rc.1resources\app.asar→package.json→version0.2.0-rc.1<install>\DeepSeek Harness.exeTwo abandoned staging directories were left next to the install (local time, UTC+8):
D:\dsh dp.new-{AF76FF91-F53F-48DD-916F-B8272379C0C3}D:\dsh dp.new-{9AFFA330-238A-497E-B0B3-FDCA67300699}Both hold a full, self-consistent app tree:
resources/app.asarwhosepackage.jsonreads0.2.0-rc.2(dshBuildCommit04f392c9ddd144fa426da2045178797da6db6c11), plus a freshly generatedUninstall DeepSeek Harness.exestamped0.2.0-rc.2. So extraction finished; only the swap into the install directory did not happen.The installer stages deliberately, then fails to swap
The cached installer is intact — SHA-512 matches
nightly.ymlbyte-for-byte (raIlxMQd9ESXgktmViW7QwVLcjBR5JIsrNOu+SpelY8kskdSr2H51/f+ey1EqFI/eIIrKQCuRANMeb5SptRZcg==, 289,313,640 bytes).7z lon it:The staging path is literally the install directory plus
.new-{GUID}— the installer resolved the correct target and deliberately staged a sibling copy of the whole payload. I scanned the packedapp.asar(which is uncompressed) for any.new-literal: 0 hits, so this staging is installer-side, not shell-side.Why the swap fails (measured, not inferred)
While the app is running, the two files the swap must replace are held open:
Ruled out:
Controlled contrast
Same cached installer, same flags as the in-app path (
--updated /S), one variable changed: everyDeepSeek Harness.exeprocess stopped and the two files above proven unlocked before launching.The package, feed, flags and install location are all fine. The only blocker is that the app's own files are still held when the swap runs.
Relationship to #8198 — and why the ack is not sufficient
#8198 identifies a real gate:
DesktopHostProcess.stop(requireGraceful = true)refuses the handoff unless the child exited with code 0 and sent ashutdown-completeack, while the host'sPROCESS_SHUTDOWN_TIMEOUT_MS = 5000force-exits before sending that ack. That gate is unchanged in 0.2.0-rc.2 (shell window is 10 s; host still 5 s).In the case reported here the gate evidently passed — the NSIS installer was genuinely launched and extracted a complete payload. So a successful
shutdown-completedoes not imply the install is replaceable. What NSIS needs is for the main Electron process to have released<install>\DeepSeek Harness.exeand<install>\resources\app.asarbefore it starts replacing them. The current gate verifies the child host's teardown, not the parent's file handles, and not the installer's outcome.Observability gap
DesktopUpdateJournal/lib/types/update-journal.js) is opt-in viaDSH_DESKTOP_UPDATE_JOURNAL_DIR. Unset by default, so a stock install records nothing at all.install-confirmedandquit-requested. AfterquitAndInstall(true, true)the process is gone, so the installer's result has no channel back into the app — even with the journal enabled, this failure is indistinguishable from success.errorstate and therefore no code.Suggested fixes (any one would help)
<install>\<exe>andresources\app.asarcan be opened for exclusive write — or simply wait for the main process to exit — before spawning the installer..new-{GUID}staging directory and record the outcome so the next launch can report it, instead of failing silently..new-{GUID}sibling exists while the feed version is still newer than the running version, surface an actionable message ("the previous update did not apply — quit the app fully and run the installer manually") instead of re-offering the same update forever.Workaround
Quit the desktop app completely — check Task Manager for
DeepSeek Harness.exe; tray/background mode keeps processes alive — then run the already-downloaded installer:It completes in about 25 seconds and the badge disappears. Confirmed on this machine after two failed in-app attempts.
中文摘要
Windows 上应用内更新静默失效:安装器确实运行了,把 rc.2 完整解压到
<安装目录>.new-{GUID}(10,916 项 / 1,015 MB,含新生成的0.2.0-rc.2卸载器),但换入安装目录这一步没有完成,旧版本原样保留,重启后徽标再次出现,全程无任何提示。已排除权限、磁盘空间、包损坏、路径含空格。实测原因:换入要替换的
DeepSeek Harness.exe与resources/app.asar正被运行中的 app 独占锁定(两者都返回 "being used by another process")。对照实验:同一个安装包、同样的--updated /S,只要在完全停掉所有进程并确认文件已解锁后运行,24 秒即成功,版本验证为 0.2.0-rc.2。与 #8198 同族但不同:那个是报错并拒绝交接(宿主 5 秒限时强制退出,
shutdown-complete从未发出);这里是优雅退出已通过、安装器真的跑了,却仍然换不进去,而且不报错。说明shutdown-complete回执不足以保证可替换——NSIS 需要的是主进程已释放<exe>与app.asar的句柄。此外DesktopUpdateJournal默认关闭(DSH_DESKTOP_UPDATE_JOURNAL_DIR),记录止于install-confirmed/quit-requested,即使开启也无法区分这种失败与成功。All reactions