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

  1. Treat the error as a normal shutdown signal: exit the accept loop without logging it as a failure
  2. Ensure clients stop dialing the plugin socket once the plugin command completes
  3. 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


AI-assisted analysis of docker/cli@e9452d6e78 (2026-08-01). Data as JSON: /data/errors/402193dc2f63340b.json. Report an issue: GitHub.