{"record":{"id":"fa15140c4a6d6cec","repo":"ginuerzh/gost","slug":"accpet-on-closed-listener-fa1514","errorCode":null,"errorMessage":"accpet on closed listener","messagePattern":"accpet on closed listener","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"tls.go","lineNumber":244,"sourceCode":"\t\t}\n\n\t\tcc := &muxStreamConn{Conn: conn, stream: stream}\n\t\tselect {\n\t\tcase l.connChan <- cc:\n\t\tdefault:\n\t\t\tcc.Close()\n\t\t\tlog.Logf(\"[mtls] %s - %s: connection queue is full\", conn.RemoteAddr(), conn.LocalAddr())\n\t\t}\n\t}\n}\n\nfunc (l *mtlsListener) Accept() (conn net.Conn, err error) {\n\tvar ok bool\n\tselect {\n\tcase conn = <-l.connChan:\n\tcase err, ok = <-l.errChan:\n\t\tif !ok {\n\t\t\terr = errors.New(\"accpet on closed listener\")\n\t\t}\n\t}\n\treturn\n}\nfunc (l *mtlsListener) Addr() net.Addr {\n\treturn l.ln.Addr()\n}\n\nfunc (l *mtlsListener) Close() error {\n\treturn l.ln.Close()\n}\n\n// Wrap a net.Conn into a client tls connection, performing any\n// additional verification as needed.\n//\n// As of go 1.3, crypto/tls only supports either doing no certificate\n// verification, or doing full verification including of the peer's\n// DNS name. For consul, we want to validate that the certificate is","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/ginuerzh/gost/blob/a33fdbf4c98034f4bfeeaea9868909822b9c526d/tls.go#L226-L262","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nfor {\n    conn, err := ln.Accept()\n    if err != nil { log.Fatal(err) }\n}\n// after\nfor {\n    conn, err := ln.Accept()\n    if err != nil {\n        if strings.Contains(err.Error(), \"closed listener\") { return nil }\n        log.Fatal(err)\n    }\n}","handlingStrategy":"try-catch","validationCode":"// no pre-call validation possible; guard the accept loop instead\nrunning := atomic.Bool{}\nrunning.Store(true)\n// set running.Store(false) before calling ln.Close()","typeGuard":null,"tryCatchPattern":"for running.Load() {\n    conn, err := ln.Accept()\n    if err != nil {\n        if strings.Contains(err.Error(), \"closed listener\") { break } // expected shutdown\n        log.Printf(\"accept: %v\", err); continue\n    }\n    go handle(conn)\n}","preventionTips":["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"],"tags":["tls","mtls","listener","accept","closed-listener"],"backgroundTag":"accept-on-closed-listener","analyzedSha":"a33fdbf4c98034f4bfeeaea9868909822b9c526d","analyzedAt":"2026-09-02T22:15:54.506Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}