AlexxIT/go2rtc · warning

pop buffer is full

Error message

pop buffer is full

What it means

Push delivers a completed data frame by sending it on the c.popBuf channel without blocking; when the channel's buffer is full (the consumer isn't draining fast enough) it returns "pop buffer is full" immediately. It is a backpressure signal: frames would otherwise block the worker or be lost, so the library fails fast instead.

Solutions

  1. Ensure a dedicated consumer goroutine continuously drains the connection's receive channel
  2. Increase the popBuf channel capacity at connection creation to absorb bursts
  3. On this error, reconnect or resync sequence numbers — the frame was NOT delivered, so handle retransmission (PushSeq sequencing helps detect gaps)
  4. Apply backpressure upstream (pause the sender or reduce inflight commands) instead of letting frames queue unboundedly

Example fix

// before
for data := range frames {
    slowProcess(data) // blocks; popBuf fills up
}
// after
go func() {
    for data := range frames {
        go slowProcess(data) // keep draining popBuf promptly
    }
}()
Defensive patterns

Strategy: fallback

Validate before calling

// drain pending frames before pushing more, or check channel occupancy
if len(popBuf) == cap(popBuf) {
    return fmt.Errorf("consumer stalled: pop buffer full")
}

Type guard

func consumerHealthy(popBuf chan []byte) bool { return len(popBuf) < cap(popBuf) }

Try / catch

if err := conn.Push(frame); err != nil {
    if strings.Contains(err.Error(), "pop buffer is full") {
        // backpressure: drop/requeue frame and resync via seq numbers
        metrics.BackpressureInc()
        return requeue(frame)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Push (via PushSeq) when the application is not draining popBuf fast enough — typically during bursts of incoming frames while the consumer is blocked, slow, or has exited.

Common situations: Consumer goroutine exited or is stuck in slow processing; burst of frames after a reconnect; popBuf capacity too small for the data rate; forgetting to consume in a fire-and-forget setup.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/f24eafd063c68263. Report an issue: GitHub.

Appendix: source

Thrown at pkg/xiaomi/miss/cs2/conn.go:448

}

func (c *dataChannel) Push(b []byte) error {
	c.waitData = append(c.waitData, b...)

	for len(c.waitData) > 4 {
		// Every new data starts with size. There can be several data inside one packet.
		if c.waitSize == 0 {
			c.waitSize = int(binary.BigEndian.Uint32(c.waitData))
			c.waitData = c.waitData[4:]
		}
		if c.waitSize > len(c.waitData) {
			break
		}

		select {
		case c.popBuf <- c.waitData[:c.waitSize]:
		default:
			return fmt.Errorf("pop buffer is full")
		}

		c.waitData = c.waitData[c.waitSize:]
		c.waitSize = 0
	}
	return nil
}

func (c *dataChannel) Pop() ([]byte, bool) {
	data, ok := <-c.popBuf
	return data, ok
}

func (c *dataChannel) Close() {
	close(c.popBuf)
}

// PushSeq returns how many seq were processed.

View on GitHub (pinned to c245815e75)