{"record":{"id":"9b2a7fd95a3dd539","repo":"multica-ai/multica","slug":"replace-binary-w","errorCode":null,"errorMessage":"replace binary: %w","messagePattern":"replace binary: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/cli/update.go","lineNumber":475,"sourceCode":"\t}\n\ttmpFile.Close()\n\n\t// Preserve original file permissions.\n\tinfo, err := os.Stat(exePath)\n\tif err != nil {\n\t\tos.Remove(tmpPath)\n\t\treturn \"\", fmt.Errorf(\"stat original binary: %w\", err)\n\t}\n\tif err := os.Chmod(tmpPath, info.Mode()); err != nil {\n\t\tos.Remove(tmpPath)\n\t\treturn \"\", fmt.Errorf(\"chmod temp file: %w\", err)\n\t}\n\n\t// Replace the original binary. On Windows this moves the running executable\n\t// aside first; on Unix a plain rename over the running inode is fine.\n\tif err := replaceBinary(tmpPath, exePath); err != nil {\n\t\tos.Remove(tmpPath)\n\t\treturn \"\", fmt.Errorf(\"replace binary: %w\", err)\n\t}\n\n\treturn fmt.Sprintf(\"Downloaded %s and replaced %s\", assetName, exePath), nil\n}\n\n// extractBinaryFromTarGz reads a .tar.gz stream and returns the contents of the\n// named file entry.\nfunc extractBinaryFromTarGz(r io.Reader, name string) ([]byte, error) {\n\tgz, err := gzip.NewReader(r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"gzip reader: %w\", err)\n\t}\n\tdefer gz.Close()\n\n\ttr := tar.NewReader(gz)\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err == io.EOF {","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/cli/update.go#L457-L493","documentation":"replaceBinary performs the final swap: on Unix a rename over the running inode; on Windows it first moves the running executable aside. Failure is wrapped as 'replace binary: %w' and the temp file removed. This is the last step, so everything before it (download, verify, extract) already succeeded.","triggerScenarios":"Windows: the running executable is locked (antivirus scanning it, another instance starting, terminal cwd inside the directory with legacy locking); Unix: EACCES on the directory (no write permission needed for the file, but for the dir), EPERM on immutable-flagged files, or EXDEV if the temp file somehow landed on another filesystem; Text-file-busy (ETXTBSY) on Linux when renaming onto a file being written/executed in edge cases.","commonSituations":"AV/EDR scanning the freshly written temp file at the exact moment of rename; users running multiple CLI instances concurrently; binaries installed with chattr +i by hardening scripts; Windows SmartScreen holding a handle.","solutions":["Retry after a moment — AV locks on the temp file are usually brief, and the poller retries the whole update on its next tick.","Ensure write permission on the binary's directory (rename needs directory write access, not file write access).","Remove the immutable flag if set (lsattr/chattr -i).","On Windows, exclude the install directory from real-time AV scanning or retry the update after the scan completes."],"exampleFix":"null","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"out, err := cli.UpdateViaDownload(ver)\nif err != nil && strings.HasPrefix(err.Error(), \"replace binary\") {\n    if errors.Is(err, fs.ErrPermission) {\n        // need write access to the install DIRECTORY (not the file)\n    } else if runtime.GOOS == \"windows\" {\n        // likely AV/another instance holding the exe: retry after delay\n        time.Sleep(5 * time.Second)\n        out, err = cli.UpdateViaDownload(ver)\n    }\n}","preventionTips":["Grant write permission on the binary's directory to the updating user","Exclude the install directory from real-time AV scans on Windows","Ensure only one process updates at a time; the poller retries failed replaces"],"tags":["filesystem","rename","windows","antivirus","self-update"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}