matryer/xbar · error

create directory %s for plugin

Error message

create directory %s for plugin

What it means

Returned by writePluginFiles when os.MkdirAll fails to create the parent directory of the destination plugin file during installation. It wraps the underlying OS error with the target directory path, so the cause is typically a filesystem permission problem or an invalid/occupied path. The library creates the directory with 0777 (before umask) before writing the plugin file into it.

Source

Thrown at pkg/plugins/install.go:117

	}
	return candidatePath, nil
}

// writePluginFiles iterates through the files defined for the plugin, and
// writes them to the plugin installation directory, and sets the entry point
// to be executable.
func (i Installer) writePluginFiles(dstPath string, plugin metadata.Plugin) error {
	if len(plugin.Files) == 0 {
		return errors.New("no plugin files")
	}
	if len(plugin.Files) > 1 {
		return errors.Errorf("only one plugin file supported: found %d.", len(plugin.Files))
	}
	for _, f := range plugin.Files {
		pluginFile := dstPath
		dir := path.Dir(pluginFile)
		if err := os.MkdirAll(dir, 0777); err != nil {
			return errors.Wrapf(err, "create directory %s for plugin", dir)
		}
		writer, err := os.Create(pluginFile)
		if err != nil {
			return errors.Wrapf(err, "create plugin file %s", f.Path)
		}
		defer writer.Close()
		reader := strings.NewReader(f.Content)
		if _, err := io.Copy(writer, reader); err != nil {
			return errors.Wrapf(err, "write plugin file %s", f.Path)
		}
		// If the Filename property of the current file matches the Filename
		// property of the plugin, this is the entry point, so set it to be
		// executable.
		if f.Filename != plugin.Filename {
			continue
		}
		if err := os.Chmod(pluginFile, 0755); err != nil {
			return errors.Wrap(err, "set executable permission on plugin entry point")

View on GitHub (pinned to d624239058)

Solutions

  1. Check and fix permissions on the parent directory (chown/chmod or run as a user with write access).
  2. Verify PluginDir/dstPath is correct and no file occupies a path component (ls the intermediate path).
  3. Ensure the filesystem is writable (not read-only mount) and path length is within limits.
  4. Pre-create the plugin directory manually with mkdir -p and correct ownership, then retry Install.

Example fix

// before (fails: ~/.upterm/plugins owned by root)
installer.Install(plugin)
// after
err := exec.Command("sudo", "chown", os.Getuid(), pluginDir).Run()
if err != nil { log.Fatal(err) }
err = installer.Install(plugin)
Defensive patterns

Strategy: validation

Validate before calling

func canWriteDir(dir string) error {
    for p := dir; ; p = filepath.Dir(p) {
        if _, err := os.Stat(p); err == nil {
            f, err := os.CreateTemp(p, ".write-test")
            if err != nil { return err }
            f.Close(); os.Remove(f.Name())
            return nil
        } else if !os.IsNotExist(err) {
            return err
        }
        if p == "/" { return os.ErrPermission }
    }
}
// call: if err := canWriteDir(filepath.Dir(dstPath)); err != nil { return err }

Try / catch

err := installer.Install(plugin)
if err != nil {
    if strings.Contains(err.Error(), "create directory") {
        var pe *os.PathError
        if errors.As(err, &pe) && os.IsPermission(pe) {
            log.Fatalf("no permission to create %s: %v", pe.Path, pe.Err)
        }
    }
    return err
}

Prevention

When it happens

Trigger: Calling Installer.Install (via writePluginFiles) when the parent directory of dstPath cannot be created: no write permission on an ancestor directory, a path component is an existing regular file, pluginDir points to read-only media, or the path is too long.

Common situations: Installing plugins into a system-wide directory as a non-root user; a stale regular file occupies part of the path; read-only container filesystem or Docker volume; PluginDir configured with a typo making an illegal path.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of matryer/xbar@d624239058 (2026-09-02). Data as JSON: /api/errors/6114263b4ad07e60. Report an issue: GitHub.