vxcontrol/pentagi · error

failed to write temporary upload file: %w

Error message

failed to write temporary upload file: %w

What it means

After creating the temp file, SaveUploadedFileToTemp copies the multipart source into it with io.Copy. If the copy fails mid-stream, the partially written temp file is removed (os.Remove) and this error is returned with the underlying cause (client disconnect, disk full, read error on the multipart stream).

Source

Thrown at backend/pkg/flowfiles/files.go:333

}

func SaveUploadedFileToTemp(fh *multipart.FileHeader, dir string) (string, error) {
	src, err := fh.Open()
	if err != nil {
		return "", fmt.Errorf("failed to open uploaded file: %w", err)
	}
	defer src.Close()

	dst, err := os.CreateTemp(dir, ".upload-*")
	if err != nil {
		return "", fmt.Errorf("failed to create temporary upload file: %w", err)
	}
	tmpPath := dst.Name()
	defer dst.Close()

	if _, err := io.Copy(dst, src); err != nil {
		os.Remove(tmpPath)
		return "", fmt.Errorf("failed to write temporary upload file: %w", err)
	}
	if err := dst.Chmod(0644); err != nil {
		os.Remove(tmpPath)
		return "", fmt.Errorf("failed to set temporary upload file permissions: %w", err)
	}

	return tmpPath, nil
}

func IsWithinDir(absPath, dir string) bool {
	return strings.HasPrefix(
		filepath.Clean(absPath)+string(filepath.Separator),
		filepath.Clean(dir)+string(filepath.Separator),
	)
}

func ResolvePulledStagedTarget(stagingDir, cacheRelPath string) string {
	candidates := []string{

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check whether the wrapped error is syscall.EPIPE / 'unexpected EOF' — the client disconnected; treat as benign client-abort and log at info level.
  2. Free disk space or raise the volume quota for the temp/upload directory.
  3. Increase reverse-proxy (nginx client_body_timeout / proxy_read_timeout) and body size limits for large uploads.
  4. Retry the upload client-side on transient network errors; the temp file is cleaned up automatically.

Example fix

// before
tmpPath, err := flowfiles.SaveUploadedFileToTemp(fh, dir)
if err != nil {
    return err
}
// after
tmpPath, err := flowfiles.SaveUploadedFileToTemp(fh, dir)
if err != nil {
    if errors.Is(err, syscall.EPIPE) || errors.Is(err, io.ErrUnexpectedEOF) {
        log.Info().Err(err).Msg("client aborted upload")
        return nil
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check rough size before streaming if the request declares Content-Length:
if r.ContentLength > maxAllowedUpload {
    http.Error(w, "file too large", http.StatusRequestEntityTooLarge)
    return
}

Try / catch

tmpPath, err := flowfiles.SaveUploadedFileToTemp(fh, dir)
if err != nil {
    if errors.Is(err, syscall.EPIPE) || errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, context.Canceled) {
        log.Info().Err(err).Msg("upload aborted by client") // temp file already cleaned up
        return
    }
    if errors.Is(err, syscall.ENOSPC) {
        http.Error(w, "storage full", http.StatusInsufficientStorage)
        return
    }
    http.Error(w, "upload failed", http.StatusInternalServerError)
    return
}

Prevention

When it happens

Trigger: io.Copy(dst, src) returns an error during UploadFlowFiles: the HTTP client disconnected mid-upload (broken pipe / context cancel), the disk filled while writing, or reading from the multipart.FileHeader failed.

Common situations: Users canceling large uploads; reverse proxies (nginx) timing out and dropping the connection; small container disk quotas exceeded by a big file; network interruption between proxy and backend.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/7bb7196ad6837504. Report an issue: GitHub.