{"record":{"id":"105956e02cc7dac1","repo":"go-delve/delve","slug":"accept-failed-listener-closed","errorCode":null,"errorMessage":"accept failed: listener closed","messagePattern":"accept failed: listener closed","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"info","filePath":"service/listenerpipe.go","lineNumber":42,"sourceCode":"type preconnectedListener struct {\n\taccepted bool\n\tconn     net.Conn\n\tclosech  chan struct{}\n\tcloseMu  sync.Mutex\n\tacceptMu sync.Mutex\n}\n\n// Accept returns the pre-established connection the first time it's called,\n// it blocks until the listener is closed on every subsequent call.\nfunc (l *preconnectedListener) Accept() (net.Conn, error) {\n\tl.acceptMu.Lock()\n\tdefer l.acceptMu.Unlock()\n\tif !l.accepted {\n\t\tl.accepted = true\n\t\treturn l.conn, nil\n\t}\n\t<-l.closech\n\treturn nil, errors.New(\"accept failed: listener closed\")\n}\n\n// Close closes the listener.\nfunc (l *preconnectedListener) Close() error {\n\tl.closeMu.Lock()\n\tdefer l.closeMu.Unlock()\n\tif l.closech == nil {\n\t\treturn nil\n\t}\n\tclose(l.closech)\n\tl.closech = nil\n\treturn nil\n}\n\n// Addr returns the listener's network address.\nfunc (l *preconnectedListener) Addr() net.Addr {\n\treturn l.conn.LocalAddr()\n}","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/service/listenerpipe.go#L24-L60","documentation":"preconnectedListener.Accept returns this error when the listener has already handed out its single pre-connected conn and has been closed. After the first Accept succeeds, Accept blocks on closech and only unblocks when Close() is called, at which point it reports that the listener is closed and can no longer accept.","triggerScenarios":"Calling Accept more than once on a preconnectedListener: the first call returns the wrapped conn, and any subsequent call blocks until Close() is invoked, then returns 'accept failed: listener closed'. Also occurs if Accept is called on a listener that was closed before the single connection was consumed.","commonSituations":"Client/server code built on listenerpipe (e.g. Delve's DAP or RPC in-process piping) where an accept loop keeps calling Accept after the single expected connection was served, or the server side shuts down while the accept loop is still running.","solutions":["Treat the single-connection contract: accept exactly one connection and stop the accept loop after the first success.","Check listener liveness before each Accept and exit the loop when Close() has been called.","Handle the returned error as a normal shutdown signal, not a failure.","If more connections are needed, use net.Listen instead of the preconnected listener."],"exampleFix":"// before\nfor {\n    conn, err := l.Accept()\n    if err != nil { log.Fatal(err) }\n    go handle(conn)\n}\n// after\nfor {\n    conn, err := l.Accept()\n    if err != nil {\n        if strings.Contains(err.Error(), \"listener closed\") {\n            return // normal shutdown\n        }\n        log.Fatal(err)\n    }\n    go handle(conn)\n    break // preconnected listener serves one connection\n}","handlingStrategy":"try-catch","validationCode":"// no pre-validation possible; track listener state yourself\nif l.isClosed() { return } // check before looping Accept","typeGuard":null,"tryCatchPattern":"conn, err := l.Accept()\nif err != nil {\n    if strings.Contains(err.Error(), \"listener closed\") {\n        return // clean shutdown, not a failure\n    }\n    return err\n}","preventionTips":["Accept only once per preconnectedListener; serve exactly one connection.","Stop accept loops when the debugger/server is shutting down.","Log this error at info level, not as a crash."],"tags":["go","listener","shutdown","accept-loop"],"backgroundTag":"listener-closed-during-accept","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}