docker/cli · error

context must be a directory

Error message

context must be a directory

What it means

Thrown by validateContextDir (used by 'docker plugin create') after Lstat'ing the PLUGIN-DATA-DIR argument: if the path is not a directory (stat.IsDir() is false), the error fires. The create command requires a directory containing a config.json file and a rootfs/ subdirectory.

Solutions

  1. Pass the directory that contains config.json and rootfs/, not the file itself.
  2. Create the required layout: a folder with config.json and a rootfs/ subdirectory.
  3. Verify with 'ls -la <path>' that the target is a directory before running.

Example fix

# before
docker plugin create myplugin ./plugin/config.json
# after
# layout: ./plugin/{config.json,rootfs/}
docker plugin create myplugin ./plugin
Defensive patterns

Strategy: type-guard

Validate before calling

// Confirm the context path is a directory before invoking plugin create
info, err := os.Stat(path)
if err != nil { return err }
if !info.IsDir() {
    return fmt.Errorf("%s is not a directory; expected a folder with config.json and rootfs/", path)
}

Type guard

func isPluginContextDir(path string) bool {
    info, err := os.Stat(path)
    return err == nil && info.IsDir()
}

Prevention

When it happens

Trigger: Running 'docker plugin create myplugin ./config.json' (passing a file) or pointing the second argument at a symlink/device that is not a directory (lines 49-56 of create.go).

Common situations: Pointing at the config.json file instead of its parent directory; passing a tar archive path; typos resolving to a regular file.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/7e261856d7c9947a. Report an issue: GitHub.

Appendix: source

Thrown at cli/command/plugin/create.go:55

	err = json.NewDecoder(dt).Decode(&m)
	_ = dt.Close()

	return err
}

// validateContextDir validates the given dir and returns its absolute path on success.
func validateContextDir(contextDir string) (string, error) {
	absContextDir, err := filepath.Abs(contextDir)
	if err != nil {
		return "", err
	}
	stat, err := os.Lstat(absContextDir)
	if err != nil {
		return "", err
	}

	if !stat.IsDir() {
		return "", errors.New("context must be a directory")
	}

	return absContextDir, nil
}

type pluginCreateOptions struct {
	repoName string
	context  string
	compress bool
}

func newCreateCommand(dockerCLI command.Cli) *cobra.Command {
	options := pluginCreateOptions{}

	cmd := &cobra.Command{
		Use:   "create [OPTIONS] PLUGIN PLUGIN-DATA-DIR",
		Short: "Create a plugin from a rootfs and configuration. Plugin data directory must contain config.json and rootfs directory.",
		Args:  cli.RequiresMinArgs(2),

View on GitHub (pinned to 4f84911bfe)