Skip to content

Add installer diagnostics guide for triaging update issues#47105

Open
LegendaryBlair wants to merge 3 commits intomainfrom
LegendaryBlair/installer-diagnostics
Open

Add installer diagnostics guide for triaging update issues#47105
LegendaryBlair wants to merge 3 commits intomainfrom
LegendaryBlair/installer-diagnostics

Conversation

@LegendaryBlair
Copy link
Copy Markdown
Contributor

Step-by-step guide for diagnosing old update installer accumulation, covering log files to check, UpdateState.json interpretation, and common root causes.

Summary of the Pull Request

PR Checklist

  • Closes: #xxx
  • Communication: I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected
  • Tests: Added/updated and all pass
  • Localization: All end-user-facing strings can be localized
  • Dev docs: Added/updated
  • New binaries: Added on the required places
  • Documentation updated: If checked, please file a pull request on our docs repo and link it here: #xxx

Detailed Description of the Pull Request / Additional comments

Validation Steps Performed

Step-by-step guide for diagnosing old update installer accumulation,
covering log files to check, UpdateState.json interpretation, and
common root causes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a developer-facing troubleshooting guide to help triage PowerToys installer/update issues—especially cases where old installers accumulate under the per-user Updates folder.

Changes:

  • Introduces a new diagnostics doc with key file paths (UpdateState.json, Runner/Update logs, Updates folder).
  • Documents UpdateState::State enum values and a step-by-step triage flow for installer accumulation scenarios.
  • Lists common root causes and log patterns to look for during investigation.

Comment on lines +57 to +59
- **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+).
Copy link

Copilot AI Apr 20, 2026

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.

Suggested change
- **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 uses AI. Check for mistakes.

### Step 3: Check if PowerToys.Update.exe has ever run

- **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.
Copy link

Copilot AI Apr 20, 2026

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.

Suggested change
- **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 uses AI. Check for mistakes.
|---|---|
| `Failed to delete installer file ... Access is denied` | File locked by AV, another process, or permissions issue |
| `Failed to delete log file ...` | Same, for old log files |
| `Failed to clean up old update files:` | Exception in cleanup (v0.73+ with exception handling) |
Copy link

Copilot AI Apr 20, 2026

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.

Suggested change
| `Failed to clean up old update files:` | Exception in cleanup (v0.73+ with exception handling) |

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +82
| 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.
Copy link

Copilot AI Apr 20, 2026

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.

Suggested change
| 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 uses AI. Check for mistakes.
- Fix incorrect claim that cleanup runs at startup for non-upToDate states;
  clarify it runs at pre-download step on v0.73+
- Soften UpdateLogs missing claim from definitive to suggestive
- Remove non-existent log message 'Failed to clean up old update files'
- Clarify that absence of cleanup logs is inconclusive since cleanup is
  silent on success
@LegendaryBlair LegendaryBlair requested a review from Copilot April 20, 2026 14:14
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 5 comments.

Comment on lines +7 to +12
| 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 |
Copy link

Copilot AI Apr 20, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +26
| 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 |
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This table has the same || issue as above and is likely to render incorrectly. Also, since these values are sourced from an enum in code, consider adding an 'As of version/commit' note here to reduce future drift if the enum changes.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +53
```json
{"state": 3, "downloadedInstallerFilename": "powertoyssetup-0.98.1-x64.exe", ...}
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code fence is marked as json, but the example isn’t valid JSON due to the .... This can mislead readers and can break tooling that validates/pretty-prints JSON snippets. Consider either removing the ellipsis and keeping the example valid JSON, or switching the fence to jsonc/text and explicitly noting fields are omitted.

Suggested change
```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 uses AI. Check for mistakes.
Comment on lines +71 to +77
| Log pattern | Meaning |
|---|---|
| `Failed to delete installer file ... Access is denied` | File locked by AV, another process, or permissions issue |
| `Failed to delete log file ...` | Same, for old log files |
| `Discovered new version` | Periodic update check ran |
| `New version is already downloaded` | State is `readyToInstall` and filename matches — no re-download, no cleanup |
| No cleanup-related entries at all | Inconclusive by itself — `cleanup_updates()` is silent on success. Corroborate with the Updates folder contents (Step 5) and the running version (Step 1). |
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Markdown table also starts rows with ||, which can cause incorrect rendering. Using a single leading | per row will keep the table readable in GitHub and other renderers.

Copilot uses AI. Check for mistakes.
| Root cause | Evidence | Fix |
|---|---|---|
| Running pre-v0.73.0 binary | `product_version` < v0.73.0 in runner log | Manually upgrade to latest |
| State stuck at `readyToInstall` (pre-v0.73) | `state: 3` in UpdateState.json, no UpdateLogs | Manually upgrade to latest |
Copy link

Copilot AI Apr 20, 2026

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.

Suggested change
| 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 |

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants