ginuerzh/gost · error

connection queue is full

Error message

connection queue is full

What it means

The DNS-over-UDP server emulation in serve() creates a virtual connection and pushes it onto the listener's connChan; if the listener's backlog of unaccepted DNS 'connections' is full (non-blocking send), it rejects the new request with this error. It signals the server is accepting requests faster than the application's ServeDNS handler consumes them.

Source

Thrown at dns.go:229

	}()

	select {
	case err := <-ln.errc:
		return nil, err
	default:
	}

	return ln, nil
}

func (l *dnsListener) serve(w dnsResponseWriter, mq []byte) (err error) {
	conn := newDNSServerConn(l.addr, w.RemoteAddr())
	conn.mq <- mq

	select {
	case l.connChan <- conn:
	default:
		return errors.New("connection queue is full")
	}

	select {
	case mr := <-conn.mr:
		_, err = w.Write(mr)
	case <-conn.cclose:
		err = io.EOF
	}
	return
}

func (l *dnsListener) ServeDNS(w dns.ResponseWriter, m *dns.Msg) {
	b, err := m.Pack()
	if err != nil {
		log.Logf("[dns] %s: %v", l.addr, err)
		return
	}
	if err := l.serve(w, b); err != nil {

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Ensure a concurrent Accept loop is running and processing connections promptly
  2. Increase accept queue capacity or spawn more handler goroutines
  3. Log and drop the request gracefully on this error (client will retry the query)
  4. Profile the handler behind Accept for blocking calls (network, locks)

Example fix

// before
conn.mq <- mq
select {
case l.connChan <- conn:
default:
    return errors.New("connection queue is full")
}
// after
select {
case l.connChan <- conn:
default:
    log.Logf("[dns] accept queue full, dropping query from %s", w.RemoteAddr())
    return errors.New("connection queue is full") // caller drops; consider resizing queue
}
Defensive patterns

Strategy: try-catch

Validate before calling

// cannot be pre-validated; concurrency/backpressure issue at accept time
if queueDepth(l.connChan) >= cap(l.connChan) {
    return fmt.Errorf("dns accept queue near capacity: %d/%d", queueDepth(l.connChan), cap(l.connChan))
}

Try / catch

if err := serve(w, r); err != nil {
    if err.Error() == "connection queue is full" {
        // drop query; DNS client will retry — optionally backpressure metric here
        return
    }
    log.Log(err)
}

Prevention

When it happens

Trigger: Calling ServeDNS/ServeHTTP for a DNS request when the DNSListener's connChan (capacity-limited accept queue) is already full — i.e., the caller of Accept() is not draining incoming DNS queries fast enough.

Common situations: A DNS tunnel server whose Accept loop is blocked or slow (downstream handler stalled), traffic spikes from DNS tunneling clients, or forgetting to start the Accept loop at all.

Related errors


AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02). Data as JSON: /api/errors/f0b6b9ae81d958f6. Report an issue: GitHub.