Skip to content

fix(updater/windows): fallback for cross-volume rename failures#5560

Merged
leaanthony merged 3 commits into
wailsapp:masterfrom
sinspired:fix/v3/windows-updater-cross-volume
Jun 10, 2026
Merged

fix(updater/windows): fallback for cross-volume rename failures#5560
leaanthony merged 3 commits into
wailsapp:masterfrom
sinspired:fix/v3/windows-updater-cross-volume

Conversation

@sinspired

@sinspired sinspired commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

On Windows, updater fails when replacing executables across different drives. When the helper attempts os.Rename, the system returns ERROR_NOT_SAME_DEVICE, causing repeated retries and eventual failure.

This patch introduces a renameOrCopy fallback:

  • First try os.Rename as usual.
  • If it fails with cross-volume error, securely copy the file and delete the source.
  • Ensure cleanup of temporary files and partial writes.
  • Sweep leftover .old files once kernel releases locks.

This fix allows portable binaries located on non-system drives (e.g. D:) to update successfully.

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Fixes # (issue)

Type of change

Please select the option that is relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration using wails doctor.

  • Windows
  • macOS
  • Linux

If you checked Linux, please specify the distro and version.

Test Configuration

Please paste the output of wails doctor. If you are unable to run this command, please describe your environment in as much detail as possible.

Checklist:

  • (v2 only) I have updated website/src/pages/changelog.mdx with details of this PR (v3 changelog entries are added automatically)
  • My code follows the general coding style of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Summary by CodeRabbit

  • Bug Fixes
    • Improved Windows update installation reliability when replacing files across different drives or volumes.
    • Added automatic fallback to safely copy and replace files if direct rename fails, reducing update failures.
    • Added rollback behavior to restore the previous file if a replacement step fails, preventing half-applied updates.

On Windows, updater fails when replacing executables across different
drives. When the helper attempts os.Rename, the system returns
ERROR_NOT_SAME_DEVICE, causing repeated retries and eventual failure.

This patch introduces a renameOrCopy fallback:
- First try os.Rename as usual.
- If it fails with cross-volume error, securely copy the file and
  delete the source.
- Ensure cleanup of temporary files and partial writes.
- Sweep leftover .old files once kernel releases locks.

This fix allows portable binaries located on non-system drives (e.g. D:)
to update successfully.
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3c94eefe-55a7-4c11-8520-52039d6b7bd4

📥 Commits

Reviewing files that changed from the base of the PR and between 63c1b66 and c2d0ed0.

📒 Files selected for processing (1)
  • v3/pkg/updater/helper_windows.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • v3/pkg/updater/helper_windows.go

Walkthrough

This PR adds safe cross-volume file replacement to the Windows updater. A new renameOrCopy helper prefers atomic rename but falls back to copy-and-delete on failure. The replaceTarget function now uses this helper and includes explicit rollback (restoring the aside file) if replacement fails, preventing partial update states.

Changes

Windows Cross-Volume File Replacement

Layer / File(s) Summary
Imports and not-same-device constant
v3/pkg/updater/helper_windows.go
Added errors and io imports and introduced a local errNotSameDevice sentinel for detecting cross-volume rename failures.
Safe file replacement and replaceTarget integration
v3/pkg/updater/helper_windows.go
Implemented renameOrCopy and copyFileExec (try os.Rename, fallback to secure copy-and-delete with mode preservation and fsync). Updated replaceTarget to use renameOrCopy and to rollback the aside target.old.* back into place if replacement fails.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • leaanthony

Poem

🐰 I hop between volumes, rename then I try,
If disks disagree, I copy and sync till I fly.
An aside kept ready, rolled back if things break,
No half-finished updates — safe steps I make.
Hooray for small helpers, and carrots for grace! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding a fallback mechanism for cross-volume rename failures on Windows updater.
Description check ✅ Passed The description covers the problem, solution, testing approach, and includes most checklist items. However, it lacks an explicit issue reference (Fixes #) and doesn't provide test configuration details.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@v3/pkg/updater/helper_windows.go`:
- Around line 47-64: renameOrCopy currently falls back to copyFileExec on any
os.Rename error; change it to only perform the copy-and-delete when the rename
error is the Windows cross-volume error (ERROR_NOT_SAME_DEVICE). Inspect the
returned error from os.Rename (likely *os.PathError), extract the underlying
syscall.Errno and compare it to syscall.ERROR_NOT_SAME_DEVICE (or numeric
17/0x11) and only call copyFileExec(src,dst) and os.Remove(src) in that case;
for any other error return the original os.Rename error unchanged. Ensure
references to renameOrCopy, copyFileExec, os.Rename, os.Remove and error
handling use the narrowed condition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0bcd4729-a5bc-422f-a580-4a43d331080a

📥 Commits

Reviewing files that changed from the base of the PR and between 7cc9bf0 and 63c1b66.

📒 Files selected for processing (1)
  • v3/pkg/updater/helper_windows.go

Comment thread v3/pkg/updater/helper_windows.go Outdated
…DEVICE only

Previously, renameOrCopy fell back to copy-and-delete on any os.Rename
error, which would silently mask unrelated failures such as ACCESS_DENIED
or a locked destination file.

Unwrap the *os.LinkError returned by os.Rename on Windows and check the
underlying syscall.Errno against ERROR_NOT_SAME_DEVICE (errno 17 / 0x11)
before triggering the copy fallback. All other errors are returned as-is
so callers see the real failure reason.
@leaanthony leaanthony enabled auto-merge (squash) June 10, 2026 21:55
@leaanthony leaanthony requested a review from Copilot June 10, 2026 21:56
@leaanthony leaanthony merged commit 2633f81 into wailsapp:master Jun 10, 2026
17 checks passed

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.

Pull request overview

This PR improves the Windows updater helper’s ability to replace the running executable when the downloaded artifact is on a different drive/volume (where os.Rename fails with ERROR_NOT_SAME_DEVICE). It introduces a renameOrCopy fallback that attempts os.Rename first and, on cross-volume errors, copies the file and then removes the source.

Changes:

  • Add renameOrCopy with Windows cross-volume detection (ERROR_NOT_SAME_DEVICE) and a copy/delete fallback.
  • Add copyFileExec to copy the executable with sync and partial-write cleanup on errors.
  • Update replaceTarget to use renameOrCopy and slightly adjust error messaging/rollback behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +70 to +75
if err := copyFileExec(src, dst); err != nil {
return fmt.Errorf("cross-volume copy %s -> %s: %w", src, dst, err)
}

_ = os.Remove(src)
return nil
Comment on lines +100 to +105
defer func() {
_ = out.Close()
if err != nil {
_ = os.Remove(dst)
}
}()
Comment on lines +93 to +95
out, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, info.Mode())
if err != nil {
return err
leaanthony added a commit that referenced this pull request Jun 13, 2026
Bundles content from the failed alpha.99 release (tag pushed but no
GitHub release created due to token misconfiguration) together with
the alpha.100 cycle. Includes:
- MacWebviewPreferences WKWebView extensions (#5549)
- generate bindings "Access is denied" fix on Windows (#5561)
- Linux frameless JS resize / scrollbar edge detection fix (#5368)
- Windows updater cross-volume rename fallback (#5560)
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