golang/go · critical
bufio: writer returned negative count from Write
Error message
bufio: writer returned negative count from Write
What it means
Go's bufio package panics with this message inside Reader.writeBuf() when an io.Writer's Write method returns a negative byte count n while draining the Reader's buffer. The io.Writer contract requires 0 <= n <= len(p); a negative value corrupts the read pointer arithmetic, so bufio aborts via panic. This is unrecoverable — it indicates a bug in the writer implementation, not a normal I/O failure.
Source
Thrown at src/bufio/bufio.go:559
for b.r < b.w {
// b.r < b.w => buffer is not empty
m, err := b.writeBuf(w)
n += m
if err != nil {
return n, err
}
b.fill() // buffer is empty
}
if b.err == io.EOF {
b.err = nil
}
return n, b.readErr()
}
var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")
// writeBuf writes the [Reader]'s buffer to the writer.
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
n, err := w.Write(b.buf[b.r:b.w])
if n < 0 {
panic(errNegativeWrite)
}
b.r += n
return int64(n), err
}
// buffered output
// Writer implements buffering for an [io.Writer] object.
// If an error occurs writing to a [Writer], no more data will be
// accepted and all subsequent writes, and [Writer.Flush], will return the error.
// After all data has been written, the client should call the
// [Writer.Flush] method to guarantee all data has been forwarded toView on GitHub (pinned to b6b368adc5)
Solutions
- Find the concrete io.Writer being written to (the argument to WriteTo / io.Copy target) and fix its Write method to return n >= 0.
- If fixing upstream is not possible, wrap the writer so a negative n is clamped to 0 and a synthetic error is returned.
- Add a regression test that writes through the suspect writer and verifies n stays non-negative across error paths.
- Re-read the io.Writer contract in package io docs: 'Write must return a non-negative number of bytes'.
Example fix
// before — buggy writer returns negative n
func (w *BadWriter) Write(p []byte) (int, error) {
if w.closed {
return -1, ErrClosed // WRONG
}
return w.dest.Write(p)
}
// after — return 0 with the error
func (w *BadWriter) Write(p []byte) (int, error) {
if w.closed {
return 0, ErrClosed
}
return w.dest.Write(p)
} Defensive patterns
Strategy: validation
Validate before calling
// Wrap any custom io.Writer before it receives data from a bufio.Reader.
type safeWriter struct{ io.Writer }
func (s safeWriter) Write(p []byte) (int, error) {
n, err := s.Writer.Write(p)
if n < 0 {
return 0, fmt.Errorf("underlying writer returned negative count %d: %w", n, err)
}
return n, err
}
// Usage:
// _, err := bufioReader.WriteTo(safeWriter{myCustomWriter}) Type guard
// Contract checker for io.Writer implementations.
func assertWriterContract(w io.Writer) error {
n, err := w.Write([]byte("x"))
if n < 0 || n > 1 {
return fmt.Errorf("writer violates contract: n=%d", n)
}
return err
} Try / catch
defer func() {
if r := recover(); r != nil {
if msg, ok := r.(string); ok && strings.Contains(msg, "negative count from Write") {
// handle: the target writer is buggy
}
panic(r)
}
}()
_, err := bufioReader.WriteTo(w) Prevention
- Never return a negative n from a custom io.Writer.Write.
- Prefer returning (0, err) for any write failure rather than a negative count.
- Test custom writers by driving them with io.Copy from a bufio.Reader.
When it happens
Trigger: Triggered when Reader.WriteTo (bufio.go:562-566) calls w.Write(b.buf[b.r:b.w]) and the returned n is < 0. Reachable through Reader.WriteTo, and indirectly via io.Copy when the source is a bufio.Reader. The culprit is always the concrete io.Writer returning a negative count.
Common situations: A custom io.Writer returns -1 or another negative number to flag an internal error instead of returning 0 bytes with a non-nil error. A writer wrapper (e.g., a counting/tee writer) that computes n with an underflowing subtraction. Stdlib writers do not produce this; it is characteristic of hand-rolled Writer implementations.
Related errors
- bufio: reader returned negative count from Read
- bufio.Scanner: token too long
- bufio.Scanner: SplitFunc returns negative advance count
- bufio.Scanner: SplitFunc returns advance count beyond input
- final token
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/24242c5b069679c8.
Report an issue: GitHub.