multica-ai/multica · error

create temp file: %w

Error message

create temp file: %w

What it means

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.

Source

Thrown at server/internal/cli/update.go:449

	binaryName := "multica"
	if runtime.GOOS == "windows" {
		binaryName = "multica.exe"
	}
	var binaryData []byte
	if runtime.GOOS == "windows" {
		binaryData, err = extractBinaryFromZip(bytes.NewReader(archiveData), binaryName)
	} else {
		binaryData, err = extractBinaryFromTarGz(bytes.NewReader(archiveData), binaryName)
	}
	if err != nil {
		return "", fmt.Errorf("extract binary: %w", err)
	}

	// Atomic replace: write to temp file, then rename over the original.
	dir := filepath.Dir(exePath)
	tmpFile, err := os.CreateTemp(dir, "multica-update-*")
	if err != nil {
		return "", fmt.Errorf("create temp file: %w", err)
	}
	tmpPath := tmpFile.Name()

	if _, err := tmpFile.Write(binaryData); err != nil {
		tmpFile.Close()
		os.Remove(tmpPath)
		return "", fmt.Errorf("write temp file: %w", err)
	}
	tmpFile.Close()

	// Preserve original file permissions.
	info, err := os.Stat(exePath)
	if err != nil {
		os.Remove(tmpPath)
		return "", fmt.Errorf("stat original binary: %w", err)
	}
	if err := os.Chmod(tmpPath, info.Mode()); err != nil {
		os.Remove(tmpPath)

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Move the binary to a user-writable location (e.g. ~/.local/bin) or run the update with sufficient privileges for that directory.
  2. Free disk space if ENOSPC.
  3. In immutable/container environments, deploy updates externally rather than in-place self-update.
  4. Check the wrapped fs.PathError for the exact directory and errno.

Example fix

# before: binary in root-owned dir, self-update fails
sudo mv multica /usr/local/bin/  # later update hits EACCES

# after: keep the binary user-writable
mkdir -p ~/.local/bin && mv multica ~/.local/bin/
Defensive patterns

Strategy: validation

Validate before calling

exe, _ := selfexec.Resolve()
exe, _ = filepath.EvalSymlinks(exe)
if info, err := os.Stat(filepath.Dir(exe)); err != nil || !info.IsDir() {
    // install dir unusable for self-update
}
// crude writability probe:
probe, err := os.CreateTemp(filepath.Dir(exe), "probe-*")
if err != nil {
    // directory not writable: do not attempt in-place update
}
probe.Close()
os.Remove(probe.Name())

Try / catch

out, err := cli.UpdateViaDownload(ver)
if err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && strings.HasPrefix(err.Error(), "create temp file") {
        // EACCES/EROFS/ENOSPC on the install dir: relocate binary or free space
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/50f10b61d028257c. Report an issue: GitHub.