Tencent/WeKnora · error

failed to save file: %w

Error message

failed to save file: %w

What it means

SaveFile wraps the error from io.Copy(dst, src) when reading the uploaded file and writing it to disk fails mid-transfer. At this point the destination file exists but is incomplete; the service returns the error without cleaning up the partial file. The wrapped error distinguishes read-side from write-side failures.

Source

Thrown at internal/application/service/file/local.go:98

		logger.Errorf(ctx, "Failed to open source file: %v", err)
		return "", fmt.Errorf("failed to open file: %w", err)
	}
	defer src.Close()

	// Create destination file for writing
	logger.Info(ctx, "Creating destination file")
	dst, err := os.Create(filePath)
	if err != nil {
		logger.Errorf(ctx, "Failed to create destination file: %v", err)
		return "", fmt.Errorf("failed to create file: %w", err)
	}
	defer dst.Close()

	// Copy content from source to destination
	logger.Info(ctx, "Copying file content")
	if _, err := io.Copy(dst, src); err != nil {
		logger.Errorf(ctx, "Failed to copy file content: %v", err)
		return "", fmt.Errorf("failed to save file: %w", err)
	}

	logger.Infof(ctx, "File saved successfully: %s", filePath)
	// Return provider:// path format: local://{relative_path}
	relPath, _ := filepath.Rel(s.baseDir, filePath)
	return localScheme + filepath.ToSlash(relPath), nil
}

// GetFile retrieves a file from the local file system by its path
// Returns a ReadCloser for reading the file content
// Supports both provider scheme: local://{relative_path} and legacy absolute paths.
// 路径必须在 baseDir 下,防止路径遍历(如 ../../)
func (s *localFileService) GetFile(ctx context.Context, filePath string) (io.ReadCloser, error) {
	logger.Infof(ctx, "Getting file: %s", filePath)

	candidate := s.normalizePathForBase(filePath)
	resolved, err := secutils.SafePathUnderBase(s.baseDir, candidate)
	if err != nil {

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Check disk space and quotas on the storage volume (df -h, quota reports)
  2. Delete the partial destination file before returning so stale partials don't linger
  3. Correlate client-disconnect logs if the wrapped error is a read failure on the source
  4. Add a pre-flight size check against free space for large uploads

Example fix

// before
if _, err := io.Copy(dst, src); err != nil {
	return "", fmt.Errorf("failed to save file: %w", err)
}
// after: clean up the partial file
if _, err := io.Copy(dst, src); err != nil {
	dst.Close()
	os.Remove(filePath)
	return "", fmt.Errorf("failed to save file: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if st, err := os.Stat(baseDir); err != nil || st.Mode().Perm()&0o200 == 0 {
	return fmt.Errorf("storage not writable")
}

Try / catch

if _, err := io.Copy(dst, src); err != nil {
	dst.Close()
	os.Remove(filePath) // remove partial file
	return fmt.Errorf("failed to save file: %w", err)
}

Prevention

When it happens

Trigger: io.Copy fails because the source multipart temp file disappears mid-read (client abort), the destination disk fills during the copy, a write error occurs on the storage volume, or an I/O timeout on a network-mounted baseDir.

Common situations: Large uploads exceeding free disk space; users cancelling uploads; NFS/EBS volume drop; per-user disk quotas hit during the copy.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/430f8777da2f45d8. Report an issue: GitHub.