ginuerzh/gost · warning
accpet on closed listener
Error message
accpet on closed listener
What it means
mtlsListener.Accept blocks on connChan/errChan; if errChan is closed (meaning the listener was shut down), it returns a literal "accpet on closed listener" error (note the upstream typo). This is the standard Go convention for Accept on a closed listener and signals that no further connections will ever be produced.
Source
Thrown at tls.go:244
}
cc := &muxStreamConn{Conn: conn, stream: stream}
select {
case l.connChan <- cc:
default:
cc.Close()
log.Logf("[mtls] %s - %s: connection queue is full", conn.RemoteAddr(), conn.LocalAddr())
}
}
}
func (l *mtlsListener) 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 *mtlsListener) Addr() net.Addr {
return l.ln.Addr()
}
func (l *mtlsListener) Close() error {
return l.ln.Close()
}
// Wrap a net.Conn into a client tls connection, performing any
// additional verification as needed.
//
// As of go 1.3, crypto/tls only supports either doing no certificate
// verification, or doing full verification including of the peer's
// DNS name. For consul, we want to validate that the certificate isView on GitHub (pinned to a33fdbf4c9)
Solutions
- Treat this error as a terminal shutdown signal: exit the accept loop instead of logging it as a failure
- Ensure Close is called exactly once and after the accept goroutine has been signaled to stop
- Use net.ErrClosed-style sentinel comparison (errors.Is / string match) to filter this error from real accept failures
Example fix
// before
for {
conn, err := ln.Accept()
if err != nil { log.Fatal(err) }
}
// after
for {
conn, err := ln.Accept()
if err != nil {
if strings.Contains(err.Error(), "closed listener") { return nil }
log.Fatal(err)
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// no pre-call validation possible; guard the accept loop instead
running := atomic.Bool{}
running.Store(true)
// set running.Store(false) before calling ln.Close() Try / catch
for running.Load() {
conn, err := ln.Accept()
if err != nil {
if strings.Contains(err.Error(), "closed listener") { break } // expected shutdown
log.Printf("accept: %v", err); continue
}
go handle(conn)
} Prevention
- Always exit accept loops on this error; never retry it
- Signal the accept goroutine to stop before calling Close
- Call Close exactly once; avoid double-close via defer and explicit paths
When it happens
Trigger: Calling Accept on an mtlsListener after Close() has been invoked (which closes the channels), or racing Close with a pending Accept in an accept loop.
Common situations: Server shutdown sequences where the accept goroutine hasn't exited before Close is called; double-Close in defer handlers; restarting the listener while the old accept loop is still draining.
Related errors
AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02).
Data as JSON: /api/errors/fa15140c4a6d6cec.
Report an issue: GitHub.