docker/cli · info
plugin server is closed
Error message
plugin server is closed
What it means
PluginServer is the unix-socket server the docker CLI uses to communicate with a running CLI plugin (e.g. for signal/teardown coordination). accept() returns this error when a new connection is accepted concurrently with Close(): after taking the mutex it finds pl.closed set, closes the just-accepted connection, and reports that the server is shut down. It exists to resolve the inherent race between Listener.Accept and Close cleanly.
Source
Thrown at cli-plugins/socket/socket.go:79
conns []net.Conn
l *net.UnixListener
h func(net.Conn)
closed bool
}
func (pl *PluginServer) accept() error {
conn, err := pl.l.Accept()
if err != nil {
return err
}
pl.mu.Lock()
defer pl.mu.Unlock()
if pl.closed {
// Handle potential race between Close and accept.
conn.Close()
return errors.New("plugin server is closed")
}
pl.conns = append(pl.conns, conn)
go pl.h(conn)
return nil
}
// Addr returns the [net.Addr] of the underlying [net.Listener].
func (pl *PluginServer) Addr() net.Addr {
return pl.l.Addr()
}
// Close ensures that the server is no longer accepting new connections and
// closes all existing connections. Existing connections will receive [io.EOF].
//
// The error value is that of the underlying [net.Listener.Close] call.
func (pl *PluginServer) Close() error {View on GitHub (pinned to e9452d6e78)
Solutions
- Treat the error as a normal shutdown signal: exit the accept loop without logging it as a failure
- Ensure clients stop dialing the plugin socket once the plugin command completes
- If seen unexpectedly mid-operation, check for premature Close() calls in teardown ordering (Close before in-flight connections were expected)
Example fix
// before
for {
if err := pl.accept(); err != nil {
log.Errorf("accept failed: %v", err)
}
}
// after
for {
if err := pl.accept(); err != nil {
return // server closed or listener error; stop accepting
}
} When it happens
Trigger: PluginServer.Close() is called (typically when the plugin command finishes or the CLI is tearing down) while the accept loop has just returned a new net.Conn from the UnixListener — the connection is dropped and accept returns this error, terminating the accept loop.
Common situations: Normal shutdown ordering — this is largely an expected, benign race-resolution path; it can surface in logs when a plugin (buildx/compose) exits while another process attempts to connect to its socket, or in tests that Close the server while dialing concurrently.
Related errors
- failed to parse hook template
- unexpected hook response type:
- plugin candidate path cannot be empty
- plugin SchemaVersion version cannot be empty
- builder prune has been cancelled
AI-assisted analysis of docker/cli@e9452d6e78 (2026-08-01).
Data as JSON: /data/errors/402193dc2f63340b.json.
Report an issue: GitHub.