grpc/grpc-go · critical
Cannot free freed buffer
Error message
Cannot free freed buffer
What it means
buffer.Free() (mem/buffers.go:155) atomically decrements the refcount and panics at line 157-159 if the result is negative - i.e. Free() was called more times than there are references. This is a double-free guard: without it the same backing slice would be returned to the BufferPool twice and handed to two unrelated callers, corrupting data.
Source
Thrown at mem/buffers.go:158
}
func (b *buffer) ReadOnlyData() []byte {
if b.rootBuf == nil {
panic("Cannot read freed buffer")
}
return b.data
}
func (b *buffer) Ref() {
if b.refs.Add(1) <= 1 {
panic("Cannot ref freed buffer")
}
}
func (b *buffer) Free() {
refs := b.refs.Add(-1)
if refs < 0 {
panic("Cannot free freed buffer")
}
if refs > 0 {
return
}
b.data = nil
if b.rootBuf == b {
// This buffer is the owner of the data slice and its ref count reached
// 0, free the slice.
if b.pool != nil {
b.pool.Put(b.origData)
b.pool = nil
}
b.origData = nil
} else {
// This buffer doesn't own the data slice, decrement a ref on the root
// buffer.
b.rootBuf.Free()View on GitHub (pinned to 0c51461d27)
Solutions
- Each owner frees exactly the references it created/obtained via Ref(); never free a reference you did not take.
- Avoid mixing `defer b.Free()` with an in-function `b.Free()`; pick one owner of each reference.
- When handing a buffer to another goroutine, Ref() first and let the receiver own (and Free) that new reference.
Example fix
// before (double free)
func process(b mem.Buffer) {
defer b.Free()
if cond {
b.Free() // second free -> panic
return
}
}
// after
func process(b mem.Buffer) {
defer b.Free() // single owner
if cond {
return
}
} Defensive patterns
Strategy: validation
Validate before calling
// Give each reference a single, clear owner that frees it exactly once.
type ref struct {
b mem.Buffer
done bool
}
func (r *ref) free() {
if r.done {
log.Print("double free avoided")
return
}
r.done = true
r.b.Free()
} Prevention
- Free only references you created via Ref() or construction.
- Do not mix `defer b.Free()` with an explicit `b.Free()` on the same reference.
- When sending a buffer to another goroutine, Ref() first and let the receiver own that reference.
When it happens
Trigger: Calling Free() twice on the same reference; two goroutines both Free()-ing a buffer that only one of them owned (forgot to Ref()); a cleanup path (defer) that frees plus an explicit Free() on the same reference.
Common situations: A defer b.Free() plus an explicit b.Free() in the same function; passing a buffer to a consumer that frees it while the producer also frees it; refcount bookkeeping bugs in custom codecs/interceptors.
Related errors
- Cannot ref freed buffer
- Cannot read freed buffer
- Cannot slice freed buffer
- Cannot split freed buffer
- slice bounds out of range [%d:%d] with length 0
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/1bf7c46a1722ed03.
Report an issue: GitHub.