{"record":{"id":"00fa1888ae5f58bd","repo":"golang/go","slug":"bytes-buffer-unreadbyte-previous-operation-was-n","errorCode":null,"errorMessage":"bytes.Buffer: UnreadByte: previous operation was not a successful read","messagePattern":"bytes\\.Buffer: UnreadByte: previous operation was not a successful read","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/bytes/buffer.go","lineNumber":425,"sourceCode":"}\n\n// UnreadRune unreads the last rune returned by [Buffer.ReadRune].\n// If the most recent read or write operation on the buffer was\n// not a successful [Buffer.ReadRune], UnreadRune returns an error.  (In this regard\n// it is stricter than [Buffer.UnreadByte], which will unread the last byte\n// from any read operation.)\nfunc (b *Buffer) UnreadRune() error {\n\tif b.lastRead <= opInvalid {\n\t\treturn errors.New(\"bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune\")\n\t}\n\tif b.off >= int(b.lastRead) {\n\t\tb.off -= int(b.lastRead)\n\t}\n\tb.lastRead = opInvalid\n\treturn nil\n}\n\nvar errUnreadByte = errors.New(\"bytes.Buffer: UnreadByte: previous operation was not a successful read\")\n\n// UnreadByte unreads the last byte returned by the most recent successful\n// read operation that read at least one byte. If a write has happened since\n// the last read, if the last read returned an error, or if the read read zero\n// bytes, UnreadByte returns an error.\nfunc (b *Buffer) UnreadByte() error {\n\tif b.lastRead == opInvalid {\n\t\treturn errUnreadByte\n\t}\n\tb.lastRead = opInvalid\n\tif b.off > 0 {\n\t\tb.off--\n\t}\n\treturn nil\n}\n\n// ReadBytes reads until the first occurrence of delim in the input,\n// returning a slice containing the data up to and including the delimiter.","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/bytes/buffer.go#L407-L443","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before — write between read and UnreadByte clears lastRead\nb, _ := buf.ReadByte()\nbuf.WriteByte('x')\nbuf.UnreadByte() // error: previous op was not a successful read\n\n// after — unread before the write, or re-read\nb, _ := buf.ReadByte()\nif pushBack { buf.UnreadByte() }\nbuf.WriteByte('x')","handlingStrategy":"validation","validationCode":"// Pair UnreadByte with a known preceding read.\nif _, err := buf.ReadByte(); err != nil { return err }\n// ... decision ...\nif shouldPushBack {\n    if err := buf.UnreadByte(); err != nil {\n        // unexpected: lastRead should be opRead here\n        return err\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := buf.UnreadByte(); err != nil {\n    if err.Error() == \"bytes.Buffer: UnreadByte: previous operation was not a successful read\" {\n        // re-read from a known offset instead of unread\n    } else {\n        return err\n    }\n}","preventionTips":["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."],"tags":["go","bytes","buffer","unread","validation"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}