{"record":{"id":"50f10b61d028257c","repo":"multica-ai/multica","slug":"create-temp-file-w","errorCode":null,"errorMessage":"create temp file: %w","messagePattern":"create temp file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/cli/update.go","lineNumber":449,"sourceCode":"\tbinaryName := \"multica\"\n\tif runtime.GOOS == \"windows\" {\n\t\tbinaryName = \"multica.exe\"\n\t}\n\tvar binaryData []byte\n\tif runtime.GOOS == \"windows\" {\n\t\tbinaryData, err = extractBinaryFromZip(bytes.NewReader(archiveData), binaryName)\n\t} else {\n\t\tbinaryData, err = extractBinaryFromTarGz(bytes.NewReader(archiveData), binaryName)\n\t}\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"extract binary: %w\", err)\n\t}\n\n\t// Atomic replace: write to temp file, then rename over the original.\n\tdir := filepath.Dir(exePath)\n\ttmpFile, err := os.CreateTemp(dir, \"multica-update-*\")\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"create temp file: %w\", err)\n\t}\n\ttmpPath := tmpFile.Name()\n\n\tif _, err := tmpFile.Write(binaryData); err != nil {\n\t\ttmpFile.Close()\n\t\tos.Remove(tmpPath)\n\t\treturn \"\", fmt.Errorf(\"write temp file: %w\", err)\n\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)","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/cli/update.go#L431-L467","documentation":"The atomic-replace strategy writes the new binary to os.CreateTemp(dir, \"multica-update-*\") in the same directory as the running executable; failure is wrapped as 'create temp file: %w'. Same-directory is required because the final rename(2) must not cross filesystems. Typical wrapped errors are fs.PathError with EACCES/EROFS/ENOSPC.","triggerScenarios":"The binary lives in a root-owned directory (/usr/local/bin) and the update runs as a non-root user; a read-only filesystem (immutable OS, squashfs container); the install directory is full (ENOSPC); macOS SIP protecting the path.","commonSituations":"Installing via a system package manager location and then expecting self-update to work unprivileged; running the daemon in a container with a read-only rootfs; disks at 100% capacity.","solutions":["Move the binary to a user-writable location (e.g. ~/.local/bin) or run the update with sufficient privileges for that directory.","Free disk space if ENOSPC.","In immutable/container environments, deploy updates externally rather than in-place self-update.","Check the wrapped fs.PathError for the exact directory and errno."],"exampleFix":"# before: binary in root-owned dir, self-update fails\nsudo mv multica /usr/local/bin/  # later update hits EACCES\n\n# after: keep the binary user-writable\nmkdir -p ~/.local/bin && mv multica ~/.local/bin/","handlingStrategy":"validation","validationCode":"exe, _ := selfexec.Resolve()\nexe, _ = filepath.EvalSymlinks(exe)\nif info, err := os.Stat(filepath.Dir(exe)); err != nil || !info.IsDir() {\n    // install dir unusable for self-update\n}\n// crude writability probe:\nprobe, err := os.CreateTemp(filepath.Dir(exe), \"probe-*\")\nif err != nil {\n    // directory not writable: do not attempt in-place update\n}\nprobe.Close()\nos.Remove(probe.Name())","typeGuard":null,"tryCatchPattern":"out, err := cli.UpdateViaDownload(ver)\nif err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && strings.HasPrefix(err.Error(), \"create temp file\") {\n        // EACCES/EROFS/ENOSPC on the install dir: relocate binary or free space\n    }\n}","preventionTips":["Install the binary in a user-writable directory","Check free disk space before large downloads","Do not rely on self-update on read-only rootfs containers"],"tags":["filesystem","permissions","temp-file","disk"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}