valyala/fasthttp · info
fasthttputil: inmemorylistener is already closed: use of clo
Error message
fasthttputil: inmemorylistener is already closed: use of closed network connection
What it means
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'.
Source
Thrown at fasthttputil/inmemory_listener.go:10
package fasthttputil
import (
"errors"
"net"
"sync"
)
// ErrInmemoryListenerClosed indicates that the InmemoryListener is already closed.
var ErrInmemoryListenerClosed = errors.New("fasthttputil: inmemorylistener is already closed: use of closed network connection")
// InmemoryListener provides in-memory dialer<->net.Listener implementation.
//
// It may be used either for fast in-process client<->server communications
// without network stack overhead or for client<->server tests.
type InmemoryListener struct {
listenerAddr net.Addr
conns chan acceptConn
done chan struct{}
addrLock sync.RWMutex
lock sync.Mutex
closed bool
}
type acceptConn struct {
conn net.Conn
accepted chan struct{}
}View on GitHub (pinned to c96f600972)
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
Example fix
// before
for {
conn, err := ln.Accept()
if err != nil { log.Fatal(err) }
go handle(conn)
}
// after
for {
conn, err := ln.Accept()
if err != nil {
if err == fasthttputil.ErrInmemoryListenerClosed {
return // clean shutdown
}
log.Fatal(err)
}
go handle(conn)
} Defensive patterns
Strategy: try-catch
Type guard
func isListenerClosed(err error) bool {
return errors.Is(err, fasthttputil.ErrInmemoryListenerClosed)
} Try / catch
conn, err := ln.Accept()
if errors.Is(err, fasthttputil.ErrInmemoryListenerClosed) {
return // graceful shutdown
} Prevention
- Check closed state before Dial/Accept in tests
- Use WaitGroups so Close happens after accept loops exit
- Handle Close racing with pending Dials explicitly
When it happens
Trigger: Calling listener.Accept() after Close(); Dial/DialWithLocalAddr while the listener is closed or concurrently closing; pending Dial calls unblocked by Close.
Common situations: 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.
Related errors
- pipeline connection has been stopped
- fasthttputil: connection closed
- only tcp, tcp4, or tcp6 is supported
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/a5b4d53876b6663e.
Report an issue: GitHub.