{"record":{"id":"a5b4d53876b6663e","repo":"valyala/fasthttp","slug":"fasthttputil-inmemorylistener-is-already-closed","errorCode":null,"errorMessage":"fasthttputil: inmemorylistener is already closed: use of closed network connection","messagePattern":"fasthttputil: inmemorylistener is already closed: use of closed network connection","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"fasthttputil/inmemory_listener.go","lineNumber":10,"sourceCode":"package fasthttputil\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"sync\"\n)\n\n// ErrInmemoryListenerClosed indicates that the InmemoryListener is already closed.\nvar ErrInmemoryListenerClosed = errors.New(\"fasthttputil: inmemorylistener is already closed: use of closed network connection\")\n\n// InmemoryListener provides in-memory dialer<->net.Listener implementation.\n//\n// It may be used either for fast in-process client<->server communications\n// without network stack overhead or for client<->server tests.\ntype InmemoryListener struct {\n\tlistenerAddr net.Addr\n\tconns        chan acceptConn\n\tdone         chan struct{}\n\taddrLock     sync.RWMutex\n\tlock         sync.Mutex\n\tclosed       bool\n}\n\ntype acceptConn struct {\n\tconn     net.Conn\n\taccepted chan struct{}\n}","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/fasthttputil/inmemory_listener.go#L1-L28","documentation":"ErrInmemoryListenerClosed is returned by InmemoryListener.Accept, Dial/DialWithLocalAddr, and related calls once the listener has been closed. It is the in-memory analogue of net's 'use of closed network connection'.","triggerScenarios":"Calling listener.Accept() after Close(); Dial/DialWithLocalAddr while the listener is closed or concurrently closing; pending Dial calls unblocked by Close.","commonSituations":"Server shutdown races where Accept loops don't stop before Close; tests closing the listener while goroutines still dial; forgetting that ErrInmemoryListenerClosed terminates the accept loop.","solutions":["Stop the Accept loop when err == ErrInmemoryListenerClosed (treat as clean shutdown)","Coordinate with sync.WaitGroup so no Dial/Accept happens after Close","Check listener state before dialing in tests; restart the listener if further connections are needed"],"exampleFix":"// before\nfor {\n    conn, err := ln.Accept()\n    if err != nil { log.Fatal(err) }\n    go handle(conn)\n}\n// after\nfor {\n    conn, err := ln.Accept()\n    if err != nil {\n        if err == fasthttputil.ErrInmemoryListenerClosed {\n            return // clean shutdown\n        }\n        log.Fatal(err)\n    }\n    go handle(conn)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isListenerClosed(err error) bool {\n    return errors.Is(err, fasthttputil.ErrInmemoryListenerClosed)\n}","tryCatchPattern":"conn, err := ln.Accept()\nif errors.Is(err, fasthttputil.ErrInmemoryListenerClosed) {\n    return // graceful shutdown\n}","preventionTips":["Check closed state before Dial/Accept in tests","Use WaitGroups so Close happens after accept loops exit","Handle Close racing with pending Dials explicitly"],"tags":["fasthttputil","inmemory","listener","shutdown"],"backgroundTag":"use-of-closed-network-connection","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}