matryer/xbar · error

set executable permission on plugin entry point

Error message

set executable permission on plugin entry point

What it means

Returned by writePluginFiles when os.Chmod fails to set mode 0755 on the installed plugin's entry-point file. The chmod makes the entry point executable so it can be invoked later. Failure means the process lacks ownership/permission on the file or the filesystem does not support permission changes.

Source

Thrown at pkg/plugins/install.go:135

			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")
		}
		// write the default variables
		plugin, err := metadata.Parse(metadata.DebugfNoop, pluginFile, f.Content)
		if err != nil {
			log.Println("install plugin: unable to parse metadata:", err)
		}
		if len(plugin.Vars) > 0 {
			defaultVars := make(map[string]interface{})
			for _, pluginVar := range plugin.Vars {
				defaultVars[pluginVar.Name] = pluginVar.DefaultValue()
			}
			err := SaveVariableValues(i.PluginDir, pluginFile, defaultVars)
			if err != nil {
				return errors.Wrap(err, "write default variables")
			}
		}
	}
	return nil

View on GitHub (pinned to d624239058)

Solutions

  1. Ensure the process owns the newly written plugin file (same user created it) and the filesystem supports Unix permissions.
  2. Verify the file still exists at pluginFile and was not modified concurrently.
  3. As a workaround, pre-set umask so created files are already executable, or chmod manually after install.
  4. Check for external interference (AV/indexers) that could remove the file mid-install.

Example fix

// before
installer.Install(plugin) // fails on FAT32 USB mount
// after
pluginDir = filepath.Join(os.Getenv("HOME"), ".upterm", "plugins") // use a native-FS location
installer := plugins.Installer{PluginDir: pluginDir}
installer.Install(plugin)
Defensive patterns

Strategy: fallback

Validate before calling

// skip check on filesystems without Unix perms
support := func(dir string) bool {
    p := filepath.Join(dir, ".permtest")
    os.WriteFile(p, []byte("x"), 0644)
    defer os.Remove(p)
    err := os.Chmod(p, 0755)
    return err == nil
}

Try / catch

err := installer.Install(plugin)
if err != nil && strings.Contains(err.Error(), "set executable permission") {
    log.Printf("chmod unsupported on this filesystem; set executable bit manually")
    // fallback: os.Chmod(pluginFile, 0755) after remount, or relocate PluginDir
    return nil
}
return err

Prevention

When it happens

Trigger: Installer.Install -> writePluginFiles, after writing the file whose f.Filename equals plugin.Filename, when os.Chmod(pluginFile, 0755) returns an error: the file was moved/replaced between create and chmod, filesystem is FAT/exFAT without permission support, or ownership was altered externally.

Common situations: Installing plugins onto a Windows-formatted or network mount that ignores chmod; security software resetting file ownership; concurrent processes manipulating the plugin directory.

Related errors


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