OpenNHP/opennhp · error

could not copy file to server

Error message

could not copy file to server: %v

What it means

After creating the form part, the file is streamed into the multipart body with io.Copy(part, progressReader). The error 'could not copy file to server: %v' wraps an io.Copy failure — typically a read error from the source file (I/O error, file removed/truncated mid-read) or a write error into the in-memory body (allocation failure). Despite the wording, at this stage nothing has been sent to the server; the copy is into a local buffer.

Solutions

  1. Check the wrapped error: read errors indicate source file/disk problems, write/allocation errors indicate memory exhaustion
  2. For very large files, ensure the host has RAM roughly equal to the file size, since body is an in-memory bytes.Buffer
  3. Verify the file is not being modified or truncated during upload
  4. Check disk health (dmesg / smartctl) for I/O errors on the source volume
  5. Consider chunked or streaming uploads (io.Pipe into http.NewRequest) for large files

Example fix

// before
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// after
// stream large files instead of buffering entirely in memory
pr, pw := io.Pipe()
writer := multipart.NewWriter(pw)
go func() {
    defer pw.Close()
    part, _ := writer.CreateFormFile("file", filepath.Base(filePath))
    io.Copy(part, progressReader)
    writer.Close()
}()
req, _ := http.NewRequest("POST", uploadUrl, pr)
Defensive patterns

Strategy: try-catch

Validate before calling

info, err := os.Stat(path)
if err != nil {
    return err
}
if uint64(info.Size()) > maxInMemoryUploadBytes {
    return fmt.Errorf("file too large for in-memory upload buffer (%d bytes)", info.Size())
}

Type guard

func fitsInMemory(path string, limit int64) bool {
    info, err := os.Stat(path)
    return err == nil && info.Size() <= limit
}

Try / catch

url, err := dev.UploadFileToNHPServer(filePath)
if err != nil {
    if strings.Contains(err.Error(), "could not copy file to server") {
        return fmt.Errorf("local copy into multipart body failed (read or OOM), no data was sent: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling UploadFileToNHPServer when the source file experiences a read I/O error mid-copy (disk failure, file truncated concurrently, NFS hiccup), or the process runs out of memory growing bytes.Buffer for a very large file.

Common situations: Uploading multi-gigabyte ZTDO files into an in-memory buffer on a memory-limited host; disk errors on the source volume; another process truncating the file during upload; OOM killer pressure.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/0dd3021060465f5e. Report an issue: GitHub.

Appendix: source

Thrown at endpoints/db/utils.go:237

	startTime := time.Now()

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	part, err := writer.CreateFormFile("file", filepath.Base(filePath))
	if err != nil {
		return "", fmt.Errorf("could not create form file: %v", err)
	}

	progressReader := &ProgressReader{
		Reader:   file,
		Progress: progress,
	}

	_, err = io.Copy(part, progressReader)
	if err != nil {
		return "", fmt.Errorf("could not copy file to server: %v", err)
	}

	err = writer.Close()
	if err != nil {
		return "", fmt.Errorf("could not close writer: %v", err)
	}

	uploadUrl := httpHost + "storage/upload"

	req, err := http.NewRequest("POST", uploadUrl, body)
	if err != nil {
		return "", fmt.Errorf("could not create request: %v", err)
	}

	req.Header.Set("Content-Type", writer.FormDataContentType())

	client := &http.Client{
		Timeout: 120 * time.Minute,

View on GitHub (pinned to 6e04ca5ff0)