gofiber/fiber · error

failed to write response body to writer

Error message

failed to write response body to writer: %w

What it means

Response.Save, given an io.Writer, copies the body stream into it with io.Copy. This wraps a failure of that copy: a read error from the response body or a write error from the supplied writer (closed pipe, buffer overflow, custom Writer erroring).

Solutions

  1. Inspect the wrapped cause to tell reader-side (network) from writer-side (your Writer) failures.
  2. Ensure the Writer remains open and writable for the entire Save call; do not close it beforehand.
  3. For long streams, set appropriate timeouts and propagate context cancellation cleanly.
Defensive patterns

Strategy: try-catch

Type guard

func isWriteCloser(v any) (io.Writer, bool) {
    w, ok := v.(io.Writer)
    return w, ok
}

Try / catch

if _, err := io.Copy(w, r.BodyStream()); err != nil {
    if errors.Is(err, io.ErrClosedPipe) || errors.Is(err, syscall.EPIPE) {
        // writer closed before body finished; abort cleanly
    }
    return err
}

Prevention

When it happens

Trigger: Passing a *pipe.Writer whose read end is closed; a bytes.Buffer that hits allocation limits; an HTTP response writer that has already been flushed/closed; a custom Writer returning an error; the upstream connection resetting mid-stream.

Common situations: Writing into an http.ResponseWriter after the client disconnected; piping into a process whose stdin closed; a streaming consumer that errors on a specific payload; network drops mid-copy.

Related errors


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

Appendix: source

Thrown at client/response.go:220

		// 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
	}
}

// Reset clears the Response object, making it ready for reuse.
func (r *Response) Reset() {
	r.client = nil
	r.request = nil
	r.respondedHost = resetOriginBuf(r.respondedHost)

View on GitHub (pinned to a105acad6c)