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

  1. Stop the Accept loop when err == ErrInmemoryListenerClosed (treat as clean shutdown)
  2. Coordinate with sync.WaitGroup so no Dial/Accept happens after Close
  3. 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

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


AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31). Data as JSON: /api/errors/a5b4d53876b6663e. Report an issue: GitHub.