docker/cli · error

plugin candidate path cannot be empty

Error message

plugin candidate path cannot be empty

What it means

newPlugin in cli-plugins/manager/plugin.go validates a plugin candidate before listing/executing it. An empty Path() from the candidate is treated as non-recoverable (unlike name/metadata problems, which are recorded on Plugin.Err), because without a filesystem path the CLI cannot derive the plugin name or execute the binary. It signals a broken candidate source rather than a broken plugin.

Source

Thrown at cli-plugins/manager/plugin.go:64

	return json.Marshal((*Alias)(&cp))
}

// pluginCandidate represents a possible plugin candidate, for mocking purposes.
type pluginCandidate interface {
	Path() string
	Metadata() ([]byte, error)
}

// newPlugin determines if the given candidate is valid and returns a
// Plugin.  If the candidate fails one of the tests then `Plugin.Err`
// is set, and is always a `pluginError`, but the `Plugin` is still
// returned with no error. An error is only returned due to a
// non-recoverable error.
func newPlugin(c pluginCandidate, cmds []*cobra.Command) (Plugin, error) {
	path := c.Path()
	if path == "" {
		return Plugin{}, errors.New("plugin candidate path cannot be empty")
	}

	// The candidate listing process should have skipped anything
	// which would fail here, so there are all real errors.
	fullname := filepath.Base(path)
	if fullname == "." {
		return Plugin{}, fmt.Errorf("unable to determine basename of plugin candidate %q", path)
	}
	var err error
	if fullname, err = trimExeSuffix(fullname); err != nil {
		return Plugin{}, fmt.Errorf("plugin candidate %q: %w", path, err)
	}
	if !strings.HasPrefix(fullname, metadata.NamePrefix) {
		return Plugin{}, fmt.Errorf("plugin candidate %q: does not have %q prefix", path, metadata.NamePrefix)
	}

	p := Plugin{
		Name: strings.TrimPrefix(fullname, metadata.NamePrefix),

View on GitHub (pinned to e9452d6e78)

Solutions

  1. Ensure the code constructing the plugin candidate passes the actual binary path (e.g. filepath.Join(dir, entry.Name()))
  2. In tests, set a non-empty path on mock candidates before calling newPlugin
  3. Check the plugin directory enumeration logic for entries with empty names being converted into candidates

Example fix

// before
c := &candidate{path: ""}
p, err := newPlugin(c, cmds)
// after
c := &candidate{path: "/usr/libexec/docker/cli-plugins/docker-example"}
p, err := newPlugin(c, cmds)

When it happens

Trigger: A pluginCandidate implementation returns "" from Path() — in practice a bug in code feeding candidates to newPlugin: a test/mock candidate with no path set, or a custom candidate enumeration that constructs candidates from empty directory-walk results.

Common situations: Mostly hit by developers embedding or extending the cli-plugins/manager package (mocks in tests, custom plugin loaders); virtually never seen by end users of the stock docker CLI, since directory scanning only yields real file paths.

Related errors


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