gofiber/fiber · error

failed to write response body to file

Error message

failed to write response body to file: %w

What it means

After creating the file, Response.Save copies the response body stream into it with io.Copy. This wraps a failure of that copy: a read error from the response body (connection reset, decompression fault, premature EOF) or a write error to the file (disk full, I/O error).

Solutions

  1. Check the wrapped cause: io.ErrUnexpectedEOF / syscall.ECONNRESET implies network, syscall.ENOSPC implies disk.
  2. Retry downloads on transient network errors; verify available disk space first for large files.
  3. Stream to a temp file and rename atomically on success to avoid partial outputs.

Example fix

// before
if err := resp.Save(dst); err != nil { ... }

// after
tmp := dst + ".part"
if err := resp.Save(tmp); err != nil { ... }
if err := os.Rename(tmp, dst); err != nil { ... }
Defensive patterns

Strategy: retry

Validate before calling

free, _ := diskFreeBytes(dstDir)
if free < int64(resp.Size()) {
    return errors.New("insufficient disk space for download")
}

Try / catch

for attempt := 0; attempt < 3; attempt++ {
    if err := resp.Save(tmp); err == nil { return os.Rename(tmp, dst) }
    var uerr *url.Error
    if !errors.As(err, &uerr) && !errors.Is(err, io.ErrUnexpectedEOF) { return err }
}

Prevention

When it happens

Trigger: The server connection drops mid-download; decompression fails; disk fills up while writing; the file's underlying device errors.

Common situations: Large downloads onto a near-full disk; flaky upstream connections; streaming responses where the server closes early; antivirus/EDR intercepting the write.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/3968b08a50a191cd. Report an issue: GitHub.

Appendix: source

Thrown at client/response.go:212

			if !errors.Is(err, fs.ErrNotExist) {
				return fmt.Errorf("failed to check directory: %w", err)
			}

			if err = os.MkdirAll(dir, 0o750); err != nil {
				return fmt.Errorf("failed to create directory: %w", err)
			}
		}

		// Create and write to file
		outFile, err := os.Create(file)
		if err != nil {
			return fmt.Errorf("failed to create file: %w", err)
		}
		defer func() { _ = outFile.Close() }() //nolint:errcheck // not needed

		// Use BodyStream() which handles both streaming and non-streaming cases
		if _, err = io.Copy(outFile, r.BodyStream()); err != nil {
			return fmt.Errorf("failed to write response body to file: %w", err)
		}

		return nil

	case io.Writer:
		// Use BodyStream() which handles both streaming and non-streaming cases
		if _, err := io.Copy(p, r.BodyStream()); err != nil {
			return fmt.Errorf("failed to write response body to writer: %w", err)
		}
		// Close the writer if it implements io.WriteCloser
		if pc, ok := p.(io.WriteCloser); ok {
			_ = pc.Close() //nolint:errcheck // not needed
		}

		return nil

	default:
		return ErrNotSupportSaveMethod

View on GitHub (pinned to a105acad6c)