kubernetes/kops · error

error renaming extracted temp dir %s -> %s: %v

Error message

error renaming extracted temp dir %s -> %s: %v

What it means

Extraction is made atomic by extracting to a temp dir then os.Rename(extractedTemp, extracted). If the rename fails — most commonly because the target path already exists or spans filesystems — addArchive returns 'error renaming extracted temp dir %s -> %s: %v'.

Source

Thrown at upup/pkg/fi/assetstore.go:319

	if _, err := os.Stat(extracted); os.IsNotExist(err) {
		// We extract to a temporary dir which we then rename so this is atomic
		// (untarring can be slow, and we might crash / be interrupted half-way through)
		extractedTemp := extracted + ".tmp-" + strconv.FormatInt(time.Now().UnixNano(), 10)
		err := os.MkdirAll(extractedTemp, 0o755)
		if err != nil {
			return fmt.Errorf("error creating directories %q: %v", path.Dir(extractedTemp), err)
		}

		args := []string{"tar", "zxf", archiveFile, "-C", extractedTemp}
		klog.Infof("running extract command %s", args)
		cmd := exec.Command(args[0], args[1:]...)
		output, err := cmd.CombinedOutput()
		if err != nil {
			return fmt.Errorf("error expanding asset file %q %v: %s", archiveFile, err, string(output))
		}

		if err := os.Rename(extractedTemp, extracted); err != nil {
			return fmt.Errorf("error renaming extracted temp dir %s -> %s: %v", extractedTemp, extracted, err)
		}
	}

	localBase := extracted
	assetBase := ""

	walker := func(localPath string, info os.FileInfo, err error) error {
		if err != nil {
			return fmt.Errorf("error descending into path %q: %v", localPath, err)
		}

		if info.IsDir() {
			return nil
		}

		relativePath, err := filepath.Rel(localBase, localPath)
		if err != nil {
			return fmt.Errorf("error finding relative path for %q: %v", localPath, err)

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check the wrapped %v for EEXIST: if the target now exists, the asset is already extracted and the operation can be retried/skipped.
  2. Remove a stale half-populated directory at the extraction path and retry.
  3. Ensure the asset store working dir and extraction target are on the same filesystem to avoid EXDEV.
  4. Avoid concurrent kOps processes sharing one asset store working directory.
  5. Fix parent directory write permissions if EACCES.

Example fix

// handle the already-extracted race
if err := os.Rename(extractedTemp, extracted); err != nil {
  if os.IsExist(err) {
    os.RemoveAll(extractedTemp) // someone else won the race; target already present
    return nil
  }
  return fmt.Errorf("error renaming extracted temp dir %s -> %s: %v", extractedTemp, extracted, err)
}
Defensive patterns

Strategy: retry

Validate before calling

import fs from "fs" // same-filesystem check before extraction
const st = fs.statSync(workDir)
if (st.dev !== fs.statSync(require("path").dirname(extracted)).dev) throw new Error("EXDEV risk: extraction target on different mount")

Type guard

function isEXDEV(err: NodeJS.ErrnoException): boolean { return err.code === "EXDEV" }
function isEEXIST(err: NodeJS.ErrnoException): boolean { return err.code === "EEXIST" }

Try / catch

try {
  await addURLs(urls)
} catch (e) {
  if (/error renaming extracted temp dir/.test(e.message)) {
    // EEXIST => asset already extracted by a racing run: safe to proceed
    // otherwise: clear stale dir and retry once
  }
  throw e
}

Prevention

When it happens

Trigger: addURLs -> addArchive where tar succeeded but os.Rename to the final extracted path fails: target dir created concurrently by another process, EXDEV (temp and target on different mounts), or EACCES on the parent.

Common situations: Concurrent kOps runs racing to extract the same asset (another process already renamed/created the target); extraction dir configured on a different mount from the working dir; leftover directory from a previously interrupted run.

Related errors


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