-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Add installer diagnostics guide for triaging update issues #47105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,94 @@ | ||||||||||||||||||||||
| # PowerToys Installer & Update Diagnostics | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| A step-by-step guide for diagnosing installer and update issues reported by users. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ## Quick Reference: Key Files | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| | File/Folder | Path | Contains | | ||||||||||||||||||||||
| |---|---|---| | ||||||||||||||||||||||
| | UpdateState.json | `%LOCALAPPDATA%\Microsoft\PowerToys\UpdateState.json` | Persisted update state machine | | ||||||||||||||||||||||
| | Runner logs | `%LOCALAPPDATA%\Microsoft\PowerToys\RunnerLogs\runner-log_*.log` | Startup, update checks, cleanup | | ||||||||||||||||||||||
| | Update logs | `%LOCALAPPDATA%\Microsoft\PowerToys\UpdateLogs\update-log_*.log` | PowerToys.Update.exe activity | | ||||||||||||||||||||||
| | Updates folder | `%LOCALAPPDATA%\Microsoft\PowerToys\Updates\` | Downloaded installer files | | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| > **Note:** These paths use `%LOCALAPPDATA%` (per-user AppData) regardless of whether PowerToys was installed per-user or per-machine. The data/settings location is always per-user. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ## Update State Values | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| From `src/common/updating/updateState.h` (`UpdateState::State` enum): | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| | Value | Name | Meaning | | ||||||||||||||||||||||
| |---|---|---| | ||||||||||||||||||||||
| | 0 | upToDate | No update needed | | ||||||||||||||||||||||
| | 1 | errorDownloading | Download or install failed, will retry | | ||||||||||||||||||||||
| | 2 | readyToDownload | New version found, not yet downloaded | | ||||||||||||||||||||||
| | 3 | readyToInstall | Installer downloaded, waiting for user action | | ||||||||||||||||||||||
| | 4 | networkError | GitHub API call failed | | ||||||||||||||||||||||
|
Comment on lines
+20
to
+26
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| --- | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ## Symptom: Old update installers accumulating on disk | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ### What to ask the user for | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| 1. Contents of `UpdateState.json` | ||||||||||||||||||||||
| 2. Runner logs (last few days from `RunnerLogs\`) | ||||||||||||||||||||||
| 3. Update logs (from `UpdateLogs\`, if they exist) | ||||||||||||||||||||||
| 4. List of files in `Updates\` folder (names + sizes) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ### Step 1: Check the running version | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| In runner logs, look for the startup line: | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ``` | ||||||||||||||||||||||
| [info] Scoobe: product_version=v0.XX.X last_version_run=v0.XX.X | ||||||||||||||||||||||
| ``` | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| - **If version < v0.73.0**: The pre-download cleanup (PR #27908) is missing. Each downloaded installer accumulates because cleanup only runs at startup when state is `upToDate`. Ask the user to manually upgrade to the latest version. | ||||||||||||||||||||||
| - **If version >= v0.73.0**: The pre-download cleanup exists. Accumulation should not happen under normal conditions. Continue to Step 2. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ### Step 2: Check UpdateState.json | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ```json | ||||||||||||||||||||||
| {"state": 3, "downloadedInstallerFilename": "powertoyssetup-0.98.1-x64.exe", ...} | ||||||||||||||||||||||
|
||||||||||||||||||||||
| ```json | |
| {"state": 3, "downloadedInstallerFilename": "powertoyssetup-0.98.1-x64.exe", ...} | |
| ```jsonc | |
| {"state": 3, "downloadedInstallerFilename": "powertoyssetup-0.98.1-x64.exe" /* additional fields may be present */} |
Copilot
AI
Apr 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The guidance for when cleanup runs is inaccurate. Runner startup cleanup is gated on UpdateState::upToDate (see src/runner/main.cpp), and updating::cleanup_updates() is otherwise only invoked right before downloading a new installer (see src/runner/UpdateUtils.cpp / src/Update/PowerToys.Update.cpp). Please reword these bullets to avoid implying cleanup runs automatically at the next startup for non-upToDate states.
| - **state = 3 (readyToInstall)**: An installer is downloaded but never installed. Cleanup at startup is skipped (by design, to preserve the pending installer). If this state persists across many update cycles, old files can accumulate on versions < v0.73.0. | |
| - **state = 1 (errorDownloading)**: A previous download or install failed. Cleanup should run at next startup (v0.73+). | |
| - **state = 2 or 4**: Transient states. Cleanup should run at next startup (v0.73+). | |
| - **state = 3 (readyToInstall)**: An installer is downloaded but never installed. Cleanup at startup is skipped (by design, to preserve the pending installer). On v0.73+, cleanup can still occur later if a future update flow reaches the pre-download cleanup path before fetching another installer. | |
| - **state = 1 (errorDownloading)**: A previous download or install failed. Do not expect automatic cleanup on the next startup; on v0.73+, cleanup is performed before a new installer download is attempted. | |
| - **state = 2 or 4**: No automatic cleanup is expected on the next startup unless the state returns to `upToDate`; on v0.73+, cleanup otherwise happens when a new installer download is about to start. |
Copilot
AI
Apr 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The statement "UpdateLogs directory missing: PowerToys.Update.exe was never launched" is too strong. PowerToys.Update.exe does not explicitly create the UpdateLogs subfolder before initializing the logger (it only ensures the root save folder exists), so missing logs could also mean logging initialization failed or logs were removed. Suggest rewording this as a possible indicator rather than a definitive conclusion.
| - **UpdateLogs directory missing**: `PowerToys.Update.exe` was never launched. The user never triggered an install — either they dismissed all update notifications, or Stage 1 failed before Stage 2 could run. | |
| - **UpdateLogs directory missing**: This suggests `PowerToys.Update.exe` may never have been launched, or may not have progressed far enough to create logs. It can also mean logging initialization failed or the logs were later removed. The user may never have triggered an install, or Stage 1 may have failed before Stage 2 could run. |
Copilot
AI
Apr 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Failed to clean up old update files: does not appear to be an emitted log message in the current cleanup implementation; updating::cleanup_updates() logs per-file failures as Failed to delete installer file ... / Failed to delete log file .... Please remove or replace this pattern with log strings that actually exist so triage steps don't send people searching for non-existent messages.
| | `Failed to clean up old update files:` | Exception in cleanup (v0.73+ with exception handling) | |
Copilot
AI
Apr 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"No cleanup-related entries at all" isn't a reliable signal that cleanup was never called: updating::cleanup_updates() only logs when deletions fail, and otherwise is silent. Consider pointing readers to call-site logs (e.g., the download trace lines) or to check the Updates folder state rather than relying on absence of cleanup logs.
| | No cleanup-related entries at all | Cleanup was never called — likely state gate blocked it | | |
| ### Step 5: Check the Updates folder contents | |
| - **All different versions**: Cleanup never ran across multiple update cycles. Points to state gate issue or pre-v0.73 binary. | |
| | No cleanup-related entries at all | Inconclusive by itself: `cleanup_updates()` is silent on success. Corroborate with call-site runner log entries (for example `Discovered new version` and download-related traces) and with the `%LOCALAPPDATA%\Microsoft\PowerToys\Updates\` folder state in Step 5. | | |
| ### Step 5: Check the Updates folder contents | |
| - **All different versions**: Cleanup likely did not run across multiple update cycles, or an older/pre-fix binary is in use. Confirm with runner log call-site traces and update state before concluding a state gate issue. |
Copilot
AI
Apr 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same || table formatting problem here. Additionally, the Evidence cell uses state: 3 while earlier examples use \"state\": 3; keeping the JSON key format consistent (and valid JSON) will reduce confusion for readers extracting the value from UpdateState.json.
| | State stuck at `readyToInstall` (pre-v0.73) | `state: 3` in UpdateState.json, no UpdateLogs | Manually upgrade to latest | | |
| | State stuck at `readyToInstall` (pre-v0.73) | `"state": 3` in UpdateState.json, no UpdateLogs | Manually upgrade to latest | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Markdown table syntax is incorrect: each row starts with
||, which typically renders as an extra empty column (or a malformed table) in many Markdown renderers. Use a single leading|for each row (and alignment row) so the table renders correctly.