Skip to content

Read winget's Own Log When an Install Fails So a Portable Package Names Its Holders - #3851

Merged
ptr727 merged 5 commits into
developfrom
fix/winget-in-use-from-winget-log
Nov 3, 2026
Merged

ptr727 merged 5 commits into
developfrom
fix/winget-in-use-from-winget-log

Conversation

@ptr727

@ptr727 ptr727 commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

Summary

A failed winget install or upgrade in host-setup/windows/install-tools.ps1 names the processes holding the tool's files only where something says files were in use. Before this change the only signals were the package's own installer log (<id>.*.log) and a short list of exit codes. A portable or zip package, astral-sh.uv among them, has no installer, so it writes no such log. winget's refusal to delete a running executable is reported under the generic 0x8A150052, so such an upgrade failed with no hint of what held the file.

  • Get-InstallerFailureReason now also reads winget's own WinGet-<timestamp>.log for the failed call. That is the latest one created at or after the attempt that names the package id, which winget logs among its arguments, and only its <E> lines are kept. The list and show probes that run before the attempt are passed over.
  • In winget's own log, an access denial naming a file (Access is denied.: "<path>") counts as files in use, as does Windows' "used by another process". A denial naming no file does not. The installer-log wording is unchanged, since an installer's "Access is denied" can be a permission failure no running process causes.
  • Select-FailureEntry is the old in-function "last few entries, keep the in-use one" logic pulled out, so both logs share it.
  • Write-InstallFailure prints a winget's own log says: block and the log's path beside the installer-log block.

This applies to every winget package rather than to uv alone. A package with an installer still reports through its installer log as before.

The comments label is on this pull request because the change corrects the header comments of both functions, which the new behavior would otherwise leave false.

Verification

  • uv run --no-project --with pytest python -m pytest tests/test_install_tools.py -q: 23 passed, 18 skipped. The new cases cover a portable package's reason read from winget's log, a longer id that only starts with the package id not being read as its log, an installer log's denial alone and a winget denial naming no file not counting as in use, and the report naming holders from winget's log.
  • The new Get-InstallerFailureReason run on a Windows 11 host against a real failed portable upgrade's DiagOutputDir selected the upgrade's own session log over the probes before it, set InUse to true, and returned the remove: Access is denied. entry.
  • Ruff, mypy, and PSScriptAnalyzer with the repository settings are clean.

Findings from the local strict review

Five recorded passes ran, the last over 10a272ba with no findings. The two introduced findings this body listed after the opening push are both fixed in 8e5a0b6b:

  • host-setup/windows/install-tools.ps1:601 (introduced): the Write-InstallFailure header said a Git upgrade that failed on a download "leaves no log", which winget's own session log made false. Fixed in 8e5a0b6b.
  • host-setup/windows/install-tools.ps1:507 (introduced): the winget-log in-use pattern accepted "access is denied" on any <E> line. Fixed in 8e5a0b6b, which counts only a denial naming a file.

The fourth pass also raised a dead empty-entry guard in Select-FailureEntry, fixed in 10a272ba. It raised one more, a denial naming a file outside the tool's install tree, such as winget's temp download folder under an antivirus lock, counting as in use. That one is declined under GOVERNANCE.md "Trust Boundaries and Hardening Effort". Its only effect is a printed suggestion naming processes running from the tool's own install tree, which is neither silent nor destructive nor one an outsider can trigger. winget logging such a denial is also unverified.

🤖 Generated with Claude Code

ptr727 and others added 3 commits November 3, 2026 08:14
…es Its Holders

A failed winget install or upgrade named the processes holding the tool's
files only where the package's installer log or winget's exit code said
files were in use. A portable or zip package has no installer, so it writes
no such log, and winget reports its refusal to delete a running executable
under a generic install-failed code. The upgrade then failed with no hint of
what held the file.

Get-InstallerFailureReason now also reads winget's own session log for the
failed call, the latest one started at or after the attempt that names the
package id, and keeps its error lines. An access denial or a sharing
violation now counts as files in use in either log, matching the exit codes
already read that way. Only processes running from the tool's own install
are ever named, so a denial over permissions blames nothing unrelated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the Two Headers

An installer log saying "Access is denied" can be a permission failure,
which no running process causes, so only winget's own log now reads a
denial or a sharing violation as files in use. The headers of
Get-InstallerFailureReason and Write-InstallFailure said only the installer
log gives a reason, which this change made false.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Write-Time Filter

The header said a sharing violation counts as files in use only in
winget's own log, but the installer-log wording already reads Windows'
"used by another process" that way. Only a denial is limited to winget's
log. A log created at or after the attempt was also written after it, so
the write-time clause filtered nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727 ptr727 added the comments Permits the comment lines the pull request adds or edits, which the prose gate otherwise refuses label Nov 3, 2026
Copilot AI lite review requested due to automatic review settings November 3, 2026 16:28
@ptr727 ptr727 added the comments Permits the comment lines the pull request adds or edits, which the prose gate otherwise refuses label Nov 3, 2026
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@ptr727

ptr727 commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 51d2f6ea43d79c3183faa20a8c61e723e6921047, the content this pull request carries at that commit against develop, and it recorded 2 findings.

…it Example

winget's own log counted any "Access is denied" error line as files in
use, while the header justifies that only for winget failing to replace a
file. Only a denial naming a file now counts. A sharing violation still
does, through the "used by another process" wording. The Write-InstallFailure
header also said a failed Git download leaves no log, which winget's own
session log made false.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Active issues remain: the documentation is inaccurate about which logs may be absent, and broad access-denied matching can misclassify unrelated WinGet failures and trigger misleading process enumeration.

2 open issues
What changed in this PR

This pull request improves failed winget install diagnostics by reading winget’s own session logs, allowing portable packages to report file-use failures and likely holding processes.

Changes:

  • Reads matching WinGet-*.log files and extracts relevant error entries.
  • Shares failure-entry selection between winget and installer logs.
  • Distinguishes winget file-removal failures from installer permission errors.
  • Expands test coverage for portable packages, log selection, denial handling, and failure reporting.

The pull request requires changes to narrow access-denied matching to file-removal diagnostics and correct the stale comment about download failures leaving no log. Package IDs containing hyphens also require corrected boundary matching.

File Description
tests/​test_install_tools.py Adds coverage for winget-log parsing, portable packages, log selection, denial handling, and failure reports.
host-setup/​windows/​install-tools.ps1 Adds winget session-log diagnostics, shared failure-entry selection, and holder reporting.

Review effort: Lite

Comment thread host-setup/windows/install-tools.ps1 Resolved
Comment thread host-setup/windows/install-tools.ps1 Resolved
Neither pattern either caller passes can match an empty string or a null,
so the match already drops every entry the guard did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.30%. Comparing base (753c536) to head (10a272b).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #3851   +/-   ##
========================================
  Coverage    83.30%   83.30%           
========================================
  Files           29       29           
  Lines         9937     9937           
========================================
  Hits          8278     8278           
  Misses        1659     1659           
Flag Coverage Δ
python-3.13 83.30% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ptr727

ptr727 commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 10a272ba9c06ab6450a6f3982ad0289c58da2a8b, the content this pull request carries at that commit against develop, and it recorded 0 findings.

@ptr727
ptr727 merged commit ab471a8 into develop Nov 3, 2026
13 checks passed
@ptr727
ptr727 deleted the fix/winget-in-use-from-winget-log branch November 3, 2026 16:54
ptr727 added a commit that referenced this pull request Nov 4, 2026
…#3856)

Promotes the changes merged into `develop` since promotion #3849 to
`main`.

- [#3851](#3851) reads
winget's own log for a failed install or upgrade in
`host-setup/windows/install-tools.ps1`, so a portable package whose
files are in use names the processes holding them.
- [#3855](#3855) runs each
`claude` child in `scripts/skills_install.py` through the path
`shutil.which` returned, so an npm `claude.cmd` shim is reached. It also
makes a report child's deadline hold on Windows, where a 3-second
deadline over a stalled git took 20.1 seconds and now takes 3.2.
Measured on native Windows 11, with the full suite passing there.
- [#3857](#3857) answers
this promotion's first review round. A locked winget log no longer
aborts the failure report, a package id in winget's own log matches
whole, and an undecodable `claude` listing reads as unknown.

Fixes #1754

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comments Permits the comment lines the pull request adds or edits, which the prose gate otherwise refuses

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants