Middle · Go foundations

Partial I/O: a short write without an error is not success

An io.Writer returns n < len(p) and nil. Is the caller allowed to report success, and how does that differ from a Reader returning data with EOF?

Try explaining this aloud before opening the answer. State your assumptions and trace a boundary case.

EXAMPLE · FRAGMENT UNLESS A COMPLETE PROGRAM IS SHOWN

go
package main

import (
	"errors"
	"fmt"
	"io"
	"strings"
)

type short struct{}

func (short) Write(p []byte) (int, error) { return len(p) / 2, nil }
func main() {
	n, err := io.Copy(short{}, strings.NewReader("hello"))
	fmt.Println(n, errors.Is(err, io.ErrShortWrite))
}
Reveal a strong answer
  1. The Writer contract requires a non-nil error when fewer than len(p) bytes are accepted. Standard copy helpers can convert a short nil-error result into io.ErrShortWrite. Preserve the accepted byte count; do not silently claim every requested byte reached the destination.

  2. Reader has a different contract: process n > 0 bytes before handling the returned error, including EOF. io.ReadFull distinguishes no available bytes from a partial fixed-size record using EOF versus ErrUnexpectedEOF. Matching method signatures does not make Reader and Writer progress/error semantics symmetric.

  3. A generic I/O loop can still block indefinitely or fail to make progress if the underlying object violates useful progress assumptions. Bound input and elapsed work at the appropriate owner, classify partial side effects and define retry/resume behavior. Test short writes, data-plus-error, empty input and truncated records rather than only bytes.Buffer success.

Common trap

Ignoring n or treating Reader and Writer error contracts as identical can silently truncate data.

Complexity & use

Well-behaved streaming copy is O(B) byte work with bounded buffers; blocking time and retry semantics depend on the underlying I/O.

Try it

Run io.Copy against a deliberately broken short writer and explain the returned count and ErrShortWrite; then compare a truncated ReadFull.

Worked solution

The short writer violates its contract. io.Copy or the source’s WriterTo implementation reports the accepted count and a short-write error, so the caller must not mark the full payload delivered. In fixed-size reads, distinguish zero-byte EOF from partial-record ErrUnexpectedEOF and process any received bytes before deciding the recovery policy.

Change the constraint

When is retrying a partially written request unsafe because the remote side may already have applied an effect?

How did you do?

Self-assessment, not a compiler pass or interview score. Explain the reasoning unaided before marking understood.

Not marked. Progress stays on this browser, separate from course completion.

Primary references

Checked 2026-10-28. Use documentation for your pinned runtime, driver and tool version.