kubernetes/kops · error

error moving downloaded file %q to %q: %v

Error message

error moving downloaded file %q to %q: %v

What it means

The final step makes the download atomic: the temp file is renamed over the destination path. If os.Rename fails, this error reports both the temp path and the destination. This guarantees partial downloads never replace a good file.

Source

Thrown at upup/pkg/fi/http.go:77

	output, err := os.CreateTemp(dir, "."+filepath.Base(destPath)+".tmp")
	if err != nil {
		return nil, fmt.Errorf("error creating temporary file for download %q: %v", destPath, err)
	}
	tempPath := output.Name()
	defer os.Remove(tempPath)

	actual, err := downloadURLToWriter(ctx, url, output, hash)
	if closeErr := output.Close(); closeErr != nil && err == nil {
		err = closeErr
	}
	if err != nil {
		return nil, err
	}
	if err := os.Chmod(tempPath, 0o644); err != nil {
		return nil, fmt.Errorf("error setting mode on downloaded file %q: %v", tempPath, err)
	}
	if err := os.Rename(tempPath, destPath); err != nil {
		return nil, fmt.Errorf("error moving downloaded file %q to %q: %v", tempPath, destPath, err)
	}
	return actual, nil
}

// downloadURLToWriter streams the file at the given url to dest.
// If hash is non-nil, it will also verify that it matches the downloaded bytes.
func downloadURLToWriter(ctx context.Context, desturl string, dest io.Writer, hash *hashing.Hash) (*hashing.Hash, error) {
	u, err := url.Parse(desturl)
	if err != nil {
		return nil, fmt.Errorf("Invalud URL for file %q: %v", desturl, err)
	}

	start := time.Now()
	defer func() {
		klog.V(2).Infof("Downloading %q took %q", desturl, time.Since(start))
	}()
	klog.V(2).Infof("Downloading %q", desturl)

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check the wrapped %v error (EXDEV, ENOENT, EACCES etc.)
  2. Verify the destination directory still exists and is writable
  3. Remove any directory occupying the destination path
  4. Re-run the download

Example fix

// before: /path/to/file is actually a directory
rm -rf /path/to/file
// after: re-run kops apply to retry the download
Defensive patterns

Strategy: try-catch

Validate before calling

if info, err := os.Lstat(destPath); err == nil && info.IsDir() {
    return fmt.Errorf("destination %s is a directory", destPath)
}

Try / catch

if _, err := fi.DownloadURL(ctx, url, dest, nil); err != nil {
    var le *os.LinkError
    if errors.As(err, &le) {
        log.Printf("rename failed: %v -> %v: %v", le.Old, le.New, le.Err)
    }
    return err
}

Prevention

When it happens

Trigger: os.Rename(tempPath, destPath) fails: cross-device link (temp and dest on different filesystems — not possible here since temp is in the same dir), dest directory removed mid-flight, or permission problems.

Common situations: Destination directory deleted or unmounted during download; a directory exists at destPath; antivirus/cleanup tooling interfering with .tmp files.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/4e559da1048deda0. Report an issue: GitHub.