ginuerzh/gost · error

accpet on closed listener

Error message

accpet on closed listener

What it means

udpListener.Accept returns this error when the listener's errChan is closed, which happens during listener shutdown. It indicates Accept was invoked on a UDP listener that has already been closed; the typo 'accpet' is part of the message itself.

Source

Thrown at udp.go:142

		select {
		case conn.rChan <- b[:n]:
			if Debug {
				log.Logf("[udp] %s >>> %s : length %d", raddr, l.Addr(), n)
			}
		default:
			log.Logf("[udp] %s -> %s : recv queue is full (%d)", raddr, l.Addr(), cap(conn.rChan))
		}
	}
}

func (l *udpListener) Accept() (conn net.Conn, err error) {
	var ok bool
	select {
	case conn = <-l.connChan:
	case err, ok = <-l.errChan:
		if !ok {
			err = errors.New("accpet on closed listener")
		}
	}
	return
}

func (l *udpListener) Addr() net.Addr {
	return l.ln.LocalAddr()
}

func (l *udpListener) Close() error {
	err := l.ln.Close()
	l.connMap.Range(func(k interface{}, v *udpServerConn) bool {
		v.Close()
		return true
	})

	return err
}

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Stop the Accept loop when this error is returned — it signals the listener is closed and will not accept again.
  2. Close the listener only after the accept goroutine has exited, or coordinate shutdown with a WaitGroup/context.
  3. Match the error (or use errors.Is on a stored sentinel) and treat it as io.ErrClosedPipe/io.EOF equivalent to terminate cleanly.

Example fix

// before
for {
    conn, err := l.Accept()
    if err != nil {
        log.Println(err) // keeps looping or logs noise
        continue
    }
}
// after
for {
    conn, err := l.Accept()
    if err != nil {
        return // exit accept loop on closed listener
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

var open atomic.Bool
// set open.Store(true) after listener creation, false after Close
if !open.Load() { return errors.New("listener already shut down") }

Type guard

func isAcceptClosedErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "closed listener")
}

Try / catch

conn, err := l.Accept()
if err != nil {
    if isAcceptClosedErr(err) { return nil } // clean shutdown
    log.Printf("accept: %v", err)
    continue
}

Prevention

When it happens

Trigger: Calling Accept on a *udpListener after Close() has been called; a serve loop continuing to Accept while another goroutine shuts the listener down.

Common situations: Server accept loops racing with graceful shutdown; forgetting to exit the accept goroutine before closing the listener; reusing a closed listener after connection errors.

Related errors


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