ginuerzh/gost · warning
accpet on closed listener
Error message
accpet on closed listener
What it means
kcpListener.Accept returns this error when the listener's errChan is closed, which happens after the listener has been closed. The (typo'd) message indicates Accept was invoked on a listener that is no longer open. It signals the accept loop to stop.
Source
Thrown at kcp.go:401
}
cc := &muxStreamConn{Conn: conn, stream: stream}
select {
case l.connChan <- cc:
default:
cc.Close()
log.Logf("[kcp] %s - %s: connection queue is full", conn.RemoteAddr(), conn.LocalAddr())
}
}
}
func (l *kcpListener) 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 *kcpListener) Addr() net.Addr {
return l.ln.Addr()
}
func (l *kcpListener) Close() error {
return l.ln.Close()
}
func blockCrypt(key, crypt, salt string) (block kcp.BlockCrypt) {
pass := pbkdf2.Key([]byte(key), []byte(salt), 4096, 32, sha1.New)
switch crypt {
case "sm4":
block, _ = kcp.NewSM4BlockCrypt(pass[:16])View on GitHub (pinned to a33fdbf4c9)
Solutions
- Stop the Accept loop when this error is returned (it means the listener is closed) — do not retry.
- Synchronize Close with accept goroutines (context cancel, sync.WaitGroup) so Accept is not called after Close.
- Treat the error as io.EOF-like termination in server code: return/exit instead of logging-and-continuing.
- Guard with a closed flag/atomic so Accept calls after Close are never issued.
Example fix
// before
for {
conn, err := ln.Accept()
if err != nil {
log.Println(err)
continue // infinite error spam after Close
}
go handle(conn)
}
// after
for {
conn, err := ln.Accept()
if err != nil {
if errors.Is(err, errClosedListener) || strings.Contains(err.Error(), "closed listener") {
return // listener closed
}
log.Println(err)
continue
}
go handle(conn)
} Defensive patterns
Strategy: try-catch
Validate before calling
select {
case <-lnClosed:
return errors.New("listener already closed")
default:
}
// then call Accept Type guard
func isClosedListenerErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "closed listener")
} Try / catch
conn, err := ln.Accept()
if err != nil {
if isClosedListenerErr(err) {
return nil // graceful shutdown
}
log.Printf("accept error: %v", err)
continue
} Prevention
- Exit the accept loop on this error instead of retrying.
- Coordinate listener Close with accept goroutines via context or WaitGroup.
- Only call Accept from a single owner goroutine with a defined shutdown order.
When it happens
Trigger: Calling Accept on a *kcpListener after Close() was called; concurrent goroutines still running accept loops when the listener is shut down; race between Close and a pending Accept.
Common situations: Server shutdown sequences where Accept loops aren't coordinated with Close; health-check or watchdog goroutines calling Accept during restart; accepting in multiple goroutines while the main thread closes the listener.
Related errors
- accpet on closed listener
- accept on closed listener
- accpet on closed listener
- closed
- kcp: wrong connection type
AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02).
Data as JSON: /api/errors/f1238f4bd14dce99.
Report an issue: GitHub.