henrygd/beszel · error

write tmp: %w

Error message

write tmp: %w

What it means

Thrown by downloadFile when io.Copy fails writing the response body into the temp file (via the optional MultiWriter that also feeds the hasher). It wraps either a disk write error or a network read error from the response body mid-transfer. The temp file is closed and removed on failure.

Source

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

		case 40:
			hasher = sha1.New()
		case 64:
			hasher = sha256.New()
		default:
			f.Close()
			os.Remove(tmp)
			return fmt.Errorf("unsupported hash length: %d (expected 40 for SHA1 or 64 for SHA256)", len(cleanSha))
		}
	}

	var mw io.Writer = f
	if hasher != nil {
		mw = io.MultiWriter(f, hasher)
	}
	if _, err := io.Copy(mw, resp.Body); err != nil {
		f.Close()
		os.Remove(tmp)
		return fmt.Errorf("write tmp: %w", err)
	}
	if err := f.Close(); err != nil {
		os.Remove(tmp)
		return fmt.Errorf("close tmp: %w", err)
	}

	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)

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Inspect the wrapped %w error: 'no space left' → free disk space; 'connection reset/unexpected EOF' → network issue
  2. Retry the download — transient network drops are the most common cause
  3. Ensure destination volume has free space larger than the binary size
  4. Increase client timeout or add resume/retry logic for large files

Example fix

// before
if _, err := io.Copy(mw, resp.Body); err != nil {
	f.Close()
	os.Remove(tmp)
	return fmt.Errorf("write tmp: %w", err)
}
// after
if _, err := io.Copy(mw, resp.Body); err != nil {
	f.Close()
	os.Remove(tmp)
	return fmt.Errorf("write tmp (disk full or connection dropped?): %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

if free, err := diskFree(filepath.Dir(dest)); err == nil && free < minRequiredBytes {
	return fmt.Errorf("only %d bytes free, need ~%d", free, minRequiredBytes)
}

Try / catch

var lastErr error
for attempt := 0; attempt < 3; attempt++ {
	lastErr = downloadFile(url, dest, sha)
	if lastErr == nil || !strings.HasPrefix(lastErr.Error(), "write tmp:") {
		break
	}
	time.Sleep(time.Duration(1<<attempt) * time.Second)
}
if lastErr != nil {
	return lastErr
}

Prevention

When it happens

Trigger: Disk fills during the download (ENOSPC), the connection drops mid-body (unexpected EOF, connection reset), or the filesystem rejects the write partway.

Common situations: Flaky Wi-Fi/CI network interrupting large downloads; full disk or small tmpfs holding the destination; proxy killing long-lived connections; quota exceeded.

Related errors


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