{"record":{"id":"fc541332e340f1ed","repo":"golang/go","slug":"bytes-buffer-too-large","errorCode":null,"errorMessage":"bytes.Buffer: too large","messagePattern":"bytes\\.Buffer: too large","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/bytes/buffer.go","lineNumber":50,"sourceCode":"// The readOp constants describe the last action performed on\n// the buffer, so that UnreadRune and UnreadByte can check for\n// invalid usage. opReadRuneX constants are chosen such that\n// converted to int they correspond to the rune size that was read.\ntype readOp int8\n\n// Don't use iota for these, as the values need to correspond with the\n// names and comments, which is easier to see when being explicit.\nconst (\n\topRead      readOp = -1 // Any other read operation.\n\topInvalid   readOp = 0  // Non-read operation.\n\topReadRune1 readOp = 1  // Read rune of size 1.\n\topReadRune2 readOp = 2  // Read rune of size 2.\n\topReadRune3 readOp = 3  // Read rune of size 3.\n\topReadRune4 readOp = 4  // Read rune of size 4.\n)\n\n// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.\nvar ErrTooLarge = errors.New(\"bytes.Buffer: too large\")\nvar errNegativeRead = errors.New(\"bytes.Buffer: reader returned negative count from Read\")\n\nconst maxInt = int(^uint(0) >> 1)\n\n// Bytes returns a slice of length b.Len() holding the unread portion of the buffer.\n// The slice is valid for use only until the next buffer modification (that is,\n// only until the next call to a method like [Buffer.Read], [Buffer.Write], [Buffer.Reset], or [Buffer.Truncate]).\n// The slice aliases the buffer content at least until the next buffer modification,\n// so immediate changes to the slice will affect the result of future reads.\nfunc (b *Buffer) Bytes() []byte { return b.buf[b.off:] }\n\n// AvailableBuffer returns an empty buffer with b.Available() capacity.\n// This buffer is intended to be appended to and\n// passed to an immediately succeeding [Buffer.Write] call.\n// The buffer is only valid until the next write operation on b.\nfunc (b *Buffer) AvailableBuffer() []byte { return b.buf[len(b.buf):] }\n\n// String returns the contents of the unread portion of the buffer","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/bytes/buffer.go#L32-L68","documentation":"bytes.Buffer panics with ErrTooLarge when it cannot allocate enough memory to grow the internal slice (buffer.go:50, re-panicked from growSlice at buffer.go:247-252). It is also used to guard against integer overflow: the buffer refuses to grow beyond maxInt. Because allocation failure is fatal to the buffer's invariants, the package panics rather than returning an error. Callers that may write unbounded data should recover or cap input.","triggerScenarios":"Triggered by any write path that calls grow/growSlice — Write, WriteString, WriteByte, WriteRune, ReadFrom — when make([]byte, newSize) panics (OOM) or the requested size overflows int. The recover in growSlice (buffer.go:248-251) converts any allocation panic into a re-panic carrying ErrTooLarge.","commonSituations":"Calling buffer.ReadFrom on an unbounded stream (network, decompression) with no size limit. Accumulating logs/responses into a Buffer that grows without bound. 32-bit builds where maxInt is ~2 GB and the buffer hits the ceiling sooner. Memory-constrained containers where make() fails at a few hundred MB.","solutions":["Cap the source before/while reading: limit with io.LimitReader, or check size before copying into the buffer.","If unbounded growth is legitimate, wrap buffer operations in a deferred recover() that treats ErrTooLarge as 'input too big'.","On 32-bit targets, switch to streaming (io.Copy to the final destination) instead of buffering the whole payload.","Raise container memory limits or switch to a chunked/file-backed buffer for very large payloads."],"exampleFix":"// before — unbounded ReadFrom can panic with ErrTooLarge\nbuf := new(bytes.Buffer)\nio.Copy(buf, resp.Body) // may OOM\n\n// after — cap the input and recover as a safety net\nbuf := new(bytes.Buffer)\nio.Copy(buf, io.LimitReader(resp.Body, maxBodyBytes))\n\n// or, guard explicitly:\ndefer func() {\n    if r := recover(); r != nil {\n        if r == bytes.ErrTooLarge { /* handle oversized input */ }\n        panic(r)\n    }\n}()","handlingStrategy":"validation","validationCode":"// Cap input size before buffering; optionally guard with recover.\nbuf := new(bytes.Buffer)\n_, err := io.Copy(buf, io.LimitReader(src, maxBytes))\nif err != nil { return err }\nif buf.Len() >= maxBytes { return ErrTooBig }","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        if r == bytes.ErrTooLarge {\n            err = fmt.Errorf(\"input exceeded buffer capacity\")\n            return\n        }\n        panic(r)\n    }\n}()\n_, err = buf.ReadFrom(src)","preventionTips":["Always bound input with io.LimitReader before copying into a bytes.Buffer.","On 32-bit builds, prefer streaming (io.Copy to the destination) over full buffering.","Monitor buffer growth in long-running services; cap at a service-level maximum."],"tags":["go","bytes","buffer","memory","panic","oom"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}