{"record":{"id":"93fff04d2efcb526","repo":"multica-ai/multica","slug":"install-new-binary-w","errorCode":null,"errorMessage":"install new binary: %w","messagePattern":"install new binary: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/cli/update_windows.go","lineNumber":44,"sourceCode":"// The leftover .old file is cleaned up on next startup via\n// CleanupStaleUpdateArtifacts.\nfunc replaceBinary(tmpPath, exePath string) error {\n\toldPath := exePath + oldBinarySuffix\n\n\t// Best-effort cleanup; if this fails (file still locked) the next Rename\n\t// will surface a useful error.\n\t_ = os.Remove(oldPath)\n\n\tif err := os.Rename(exePath, oldPath); err != nil {\n\t\treturn fmt.Errorf(\"move running binary aside: %w\", err)\n\t}\n\n\tif err := os.Rename(tmpPath, exePath); err != nil {\n\t\t// Restore so the user isn't left without a multica.exe.\n\t\tif rerr := os.Rename(oldPath, exePath); rerr != nil {\n\t\t\treturn fmt.Errorf(\"install new binary: %w (and failed to restore: %v)\", err, rerr)\n\t\t}\n\t\treturn fmt.Errorf(\"install new binary: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// CleanupStaleUpdateArtifacts removes leftover `.old` binaries from previous\n// updates. Windows can't delete a running .exe, so a prior update may have\n// left one behind; once the user restarts, this call reclaims the space.\nfunc CleanupStaleUpdateArtifacts() {\n\texePath, err := selfexec.Resolve()\n\tif err != nil {\n\t\treturn\n\t}\n\tif resolved, err := filepath.EvalSymlinks(exePath); err == nil {\n\t\texePath = resolved\n\t}\n\t_ = os.Remove(exePath + oldBinarySuffix)\n}","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/cli/update_windows.go#L26-L62","documentation":"Windows-only replaceBinary failure where the new binary could not be moved into place, but the rollback succeeded: the original executable was restored from the .old name, so the installation is intact at the previous version. Typical root causes mirror 865 (AV lock on the fresh file, permissions, disk state) but recovery already happened.","triggerScenarios":"Self-update where os.Rename(tmpPath, exePath) fails — most commonly antivirus holding the just-downloaded temp binary, the temp file being on a different volume with restrictive ACLs, or the destination briefly locked by a scanner — and the restore rename then succeeds.","commonSituations":"First update attempt on machines with real-time AV scanning; temp dir on a different drive than the install; transient sharing violations on Windows.","solutions":["Retry the update — transient sharing violations usually clear within seconds","Add an AV exclusion for the install and temp directories if it repeats","Ensure the temp binary lands on the same volume as the install (avoids cross-volume rename edge cases)","Check disk space and directory permissions on the install path"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Ensure temp file is on the same volume as the exe before attempting replace.\ntmpDir := filepath.Dir(exePath)\ntmp, err := os.CreateTemp(tmpDir, \"multica-update-*\")\nif err != nil {\n    return fmt.Errorf(\"stage download beside exe: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"Since the original was restored, the safe pattern is: log 'update failed, still on version X', wait a few seconds, retry the whole download+replace once. Check ERROR_SHARING_VIOLATION to distinguish AV locks.","preventionTips":["Download the new binary to a temp file in the install directory (same volume)","Retry updates on transient sharing violations instead of failing the update permanently","Keep AV exclusions current after install-path changes"],"tags":["windows","self-update","rollback","retryable"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}