golang/go · error
bytes.Buffer: UnreadByte: previous operation was not a succe
Error message
bytes.Buffer: UnreadByte: previous operation was not a successful read
What it means
bytes.Buffer.UnreadByte returns errUnreadByte when the most recent operation was not a successful read (buffer.go:425-428, guarded by b.lastRead == opInvalid). lastRead is opInvalid after writes, after Reset, before any read, or after an unread has already been consumed. Unlike UnreadRune, UnreadByte accepts any successful read op (opRead or opReadRuneX).
Source
Thrown at src/bytes/buffer.go:425
}
// UnreadRune unreads the last rune returned by [Buffer.ReadRune].
// If the most recent read or write operation on the buffer was
// not a successful [Buffer.ReadRune], UnreadRune returns an error. (In this regard
// it is stricter than [Buffer.UnreadByte], which will unread the last byte
// from any read operation.)
func (b *Buffer) UnreadRune() error {
if b.lastRead <= opInvalid {
return errors.New("bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune")
}
if b.off >= int(b.lastRead) {
b.off -= int(b.lastRead)
}
b.lastRead = opInvalid
return nil
}
var errUnreadByte = errors.New("bytes.Buffer: UnreadByte: previous operation was not a successful read")
// UnreadByte unreads the last byte returned by the most recent successful
// read operation that read at least one byte. If a write has happened since
// the last read, if the last read returned an error, or if the read read zero
// bytes, UnreadByte returns an error.
func (b *Buffer) UnreadByte() error {
if b.lastRead == opInvalid {
return errUnreadByte
}
b.lastRead = opInvalid
if b.off > 0 {
b.off--
}
return nil
}
// ReadBytes reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and including the delimiter.View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure the immediately preceding successful Buffer operation was a read before calling UnreadByte.
- Avoid double-unread: only one pushback is valid; track it in parser state.
- If you must unread after a write, restructure so the write happens after the unread, or re-read from a known offset.
- Pair each UnreadByte call with a specific preceding read in the code so the invariant is locally obvious.
Example fix
// before — write between read and UnreadByte clears lastRead
b, _ := buf.ReadByte()
buf.WriteByte('x')
buf.UnreadByte() // error: previous op was not a successful read
// after — unread before the write, or re-read
b, _ := buf.ReadByte()
if pushBack { buf.UnreadByte() }
buf.WriteByte('x') Defensive patterns
Strategy: validation
Validate before calling
// Pair UnreadByte with a known preceding read.
if _, err := buf.ReadByte(); err != nil { return err }
// ... decision ...
if shouldPushBack {
if err := buf.UnreadByte(); err != nil {
// unexpected: lastRead should be opRead here
return err
}
} Try / catch
if err := buf.UnreadByte(); err != nil {
if err.Error() == "bytes.Buffer: UnreadByte: previous operation was not a successful read" {
// re-read from a known offset instead of unread
} else {
return err
}
} Prevention
- Ensure the immediately preceding Buffer op was a successful read before UnreadByte.
- Never call UnreadByte twice without an intervening read.
- Avoid interleaving writes between the read and the unread.
When it happens
Trigger: Triggered by calling buffer.UnreadByte() when lastRead == opInvalid: after a Write/WriteString/WriteByte, after Reset, before the first read, or after a prior UnreadByte/UnreadRune already reset lastRead to opInvalid.
Common situations: Interleaving a write between a read and UnreadByte. Calling UnreadByte twice in a row (the second call sees opInvalid). Speculative unread in a tokenizer without verifying the prior op was a read.
Related errors
- bytes.Buffer: UnreadRune: previous operation was not a succe
- bytes.Reader.UnreadByte: at beginning of slice
- bytes.Reader.UnreadRune: at beginning of slice
- bytes.Reader.UnreadRune: previous operation was not ReadRune
- bytes.Buffer: truncation out of range
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/00fa1888ae5f58bd.
Report an issue: GitHub.