plandex-ai/plandex · error

failed to save the downloaded archive: %w

Error message

failed to save the downloaded archive: %w

What it means

doUpgrade streams the HTTP response body into the temp file with io.Copy. If the write fails mid-transfer (disk full, I/O error) or reading the response body fails (connection reset mid-download), it returns 'failed to save the downloaded archive: %w'. Note io.Copy also surfaces read errors from resp.Body, so truncated network transfers land here too.

Source

Thrown at app/cli/upgrade.go:120

	downloadURL := fmt.Sprintf("https://github.com/plandex-ai/plandex/releases/download/%s/plandex_%s_%s_%s.tar.gz", escapedTag, version, runtime.GOOS, runtime.GOARCH)
	resp, err := http.Get(downloadURL)
	if err != nil {
		return fmt.Errorf("failed to download the update: %w", err)
	}
	defer resp.Body.Close()

	// Create a temporary file to save the downloaded archive
	tempFile, err := os.CreateTemp("", "*.tar.gz")
	if err != nil {
		return fmt.Errorf("failed to create temporary file: %w", err)
	}
	defer os.Remove(tempFile.Name()) // Clean up file afterwards

	// Copy the response body to the temporary file
	_, err = io.Copy(tempFile, resp.Body)
	if err != nil {
		return fmt.Errorf("failed to save the downloaded archive: %w", err)
	}

	_, err = tempFile.Seek(0, 0)
	if err != nil {
		return fmt.Errorf("failed to seek in temporary file: %w", err)
	}

	// Now, extract the binary from the tempFile
	gzr, err := gzip.NewReader(tempFile)
	if err != nil {
		return fmt.Errorf("failed to create gzip reader: %w", err)
	}
	defer gzr.Close()

	tarReader := tar.NewReader(gzr)
	for {
		header, err := tarReader.Next()
		if err == io.EOF {

View on GitHub (pinned to e2d772072e)

Solutions

  1. Free disk space on the temp filesystem.
  2. Retry the upgrade on a stable connection.
  3. Check TMPDIR for a faster/larger filesystem and set TMPDIR accordingly.
  4. Download the release manually and install it if the network keeps dropping.

Example fix

// before (no size/status checks before copy)
_, err = io.Copy(tempFile, resp.Body)
// after (validate status and use a size-aware copy)
if resp.StatusCode != http.StatusOK {
	return fmt.Errorf("unexpected download status: %s", resp.Status)
}
if _, err = io.Copy(tempFile, resp.Body); err != nil {
	return fmt.Errorf("failed to save the downloaded archive: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

if resp.StatusCode != http.StatusOK {
	return fmt.Errorf("download failed: %s", resp.Status)
}
// pre-check free space when Content-Length is known
if resp.ContentLength > 0 {
	if st, err := os.Stat(os.TempDir()); err == nil {
		_ = st // additionally use syscall.Statfs for free space in production
	}
}

Try / catch

n, err := io.Copy(tempFile, resp.Body)
if err != nil {
	if resp.ContentLength > 0 && n < resp.ContentLength {
		return fmt.Errorf("truncated download (%d/%d bytes): %w", n, resp.ContentLength, err)
	}
	return fmt.Errorf("failed to save the downloaded archive: %w", err)
}

Prevention

When it happens

Trigger: io.Copy(tempFile, resp.Body) errors: out of disk space while writing the archive, interrupted network connection during the download, or storage device I/O error.

Common situations: Full /tmp partition on a large release download; flaky Wi-Fi dropping mid-download; proxy terminating long transfers; disk quota exceeded.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/2054e65909987b10. Report an issue: GitHub.