henrygd/beszel · error

rename: %w

Error message

rename: %w

What it means

After chmod succeeds, downloadFile atomically moves the temp file to its final destination with os.Rename. A wrapped `rename: %w` error means the move failed and the temp file was deleted. Rename typically fails when source and destination are on different filesystems or the destination is not writable.

Source

Thrown at agent/tools/fetchsmartctl/main.go:120

	}

	if hasher != nil && shaHex != "" {
		cleanSha := strings.ToLower(strings.ReplaceAll(strings.TrimSpace(shaHex), " ", ""))
		got := strings.ToLower(hex.EncodeToString(hasher.Sum(nil)))
		if got != cleanSha {
			os.Remove(tmp)
			return fmt.Errorf("hash mismatch: got %s want %s", got, cleanSha)
		}
	}

	// Make executable and move into place
	if err := os.Chmod(tmp, 0o755); err != nil {
		os.Remove(tmp)
		return fmt.Errorf("chmod: %w", err)
	}
	if err := os.Rename(tmp, dest); err != nil {
		os.Remove(tmp)
		return fmt.Errorf("rename: %w", err)
	}

	fmt.Println("smartctl.exe downloaded to", dest)
	return nil
}

func fatalf(format string, a ...any) {
	fmt.Fprintf(os.Stderr, format+"\n", a...)
	os.Exit(1)
}

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Ensure the destination directory exists and is writable (sufficient privileges or a user-writable path).
  2. Set TMPDIR (or the temp path) to a directory on the same filesystem as the destination to avoid EXDEV, or add a copy-based fallback.
  3. Retry if the cause was a transient lock (antivirus/another process); avoid running multiple instances concurrently.
  4. Read the wrapped error's errno: ENOENT → create dest dir; EXDEV → same-fs temp; EACCES → fix permissions.

Example fix

// before
if err := os.Rename(tmp, dest); err != nil {
	return fmt.Errorf("rename: %w", err)
}
// after
if err := os.Rename(tmp, dest); err != nil {
	if errors.Is(err, syscall.EXDEV) {
		if cerr := copyFile(tmp, dest); cerr != nil {
			return fmt.Errorf("rename: %w", err)
		}
	} else {
		return fmt.Errorf("rename: %w", err)
	}
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure dest dir exists and temp and dest share a filesystem
if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {
	return err
}
tmp := filepath.Join(filepath.Dir(dest), ".fetch-tmp") // same device as dest

Try / catch

if err := downloadFile(url, dest, sha); err != nil {
	if strings.HasPrefix(err.Error(), "rename:") {
		log.Printf("rename failed (cross-device or locked dest?): %v", err)
	} else {
		return err
	}
}

Prevention

When it happens

Trigger: os.Rename(tmp, dest) errors: temp dir and dest are on different mounts/devices (EXDEV), dest directory doesn't exist or lacks write permission, dest is locked by another process (Windows), or tmp vanished.

Common situations: TMPDIR on tmpfs while dest is on another disk; installing to a read-only or root-owned directory without privileges; concurrent runs racing over the same dest file; antivirus holding the file open.

Related errors


AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31). Data as JSON: /api/errors/1912d13221ff0509. Report an issue: GitHub.