multica-ai/multica · critical
install new binary: %w (and failed to restore: %v)
Error message
install new binary: %w (and failed to restore: %v)
What it means
Windows-only replaceBinary failure where BOTH renames failed: moving the new binary into place failed AND rolling the original back from the .old name failed. The install is now in a broken state — no exe exists at exePath (the original sits at exePath+'.old'), so multica.exe cannot start until it is restored manually.
Source
Thrown at server/internal/cli/update_windows.go:42
// 4. If step 3 fails, restore the original so the user isn't stranded.
//
// The leftover .old file is cleaned up on next startup via
// CleanupStaleUpdateArtifacts.
func replaceBinary(tmpPath, exePath string) error {
oldPath := exePath + oldBinarySuffix
// Best-effort cleanup; if this fails (file still locked) the next Rename
// will surface a useful error.
_ = os.Remove(oldPath)
if err := os.Rename(exePath, oldPath); err != nil {
return fmt.Errorf("move running binary aside: %w", err)
}
if err := os.Rename(tmpPath, exePath); err != nil {
// Restore so the user isn't left without a multica.exe.
if rerr := os.Rename(oldPath, exePath); rerr != nil {
return fmt.Errorf("install new binary: %w (and failed to restore: %v)", err, rerr)
}
return fmt.Errorf("install new binary: %w", err)
}
return nil
}
// CleanupStaleUpdateArtifacts removes leftover `.old` binaries from previous
// updates. Windows can't delete a running .exe, so a prior update may have
// left one behind; once the user restarts, this call reclaims the space.
func CleanupStaleUpdateArtifacts() {
exePath, err := selfexec.Resolve()
if err != nil {
return
}
if resolved, err := filepath.EvalSymlinks(exePath); err == nil {
exePath = resolved
}View on GitHub (pinned to 2c0912b6ec)
Solutions
- Manually restore: rename multica.exe.old back to multica.exe in the install directory
- Terminate every process holding either file (Resource Monitor > CPU > Associated Handles) or simply reboot, then restore/reinstall
- Add AV exclusions for the install directory before retrying the update
- Reinstall from the release artifact if the .old file is gone or corrupt
Defensive patterns
Strategy: fallback
Validate before calling
// Before update: verify both source and destination renames are likely to succeed.
func canReplace(tmpPath, exePath string) error {
if _, err := os.Stat(tmpPath); err != nil {
return fmt.Errorf("new binary missing: %w", err)
}
if fi, err := os.Stat(filepath.Dir(exePath)); err != nil || !fi.IsDir() {
return fmt.Errorf("install directory unavailable: %w", err)
}
return nil
} Try / catch
On this error, immediately print a recovery instruction: 'rename <exePath>.old back to <exePath> or reinstall' — the app must not continue silently with no exe in place.
Prevention
- Stop all instances of the binary before updating
- Keep AV exclusions on both install and temp directories
- Have the installer/updater write a recovery script next to the exe before starting the swap
When it happens
Trigger: The new binary at tmpPath became locked (AV grabbed the freshly downloaded file between the two renames) at the same time the .old file was also locked (another process still running the old image), or the directory ACL changed mid-update.
Common situations: Aggressive AV/EDR scanning new binaries while a second multica process still runs the old one; transient filesystem errors on network mounts; disk-full conditions on the install volume.
Related errors
- move running binary aside: %w
- replace binary: %w
- install new binary: %w
- no matching release asset for %s/%s (tried: %s)
- brew upgrade failed: %w
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/5492bc5066d93ba2.
Report an issue: GitHub.