matryer/xbar · error

open plugin source

Error message

open plugin source

What it means

loadVariablesFromPluginMetadata (pkg/plugins/variables.go:123-125) wraps os.Open failures on the plugin executable itself (p.Command) with 'open plugin source'. The library reads the plugin's source to parse `<xbar.var>` default variable declarations, so if the executable cannot be opened, defaults cannot be loaded and the error propagates up through loadVariables ('load default vars').

Source

Thrown at pkg/plugins/variables.go:125

		return nil, errors.Wrap(err, "open vars json file")
	}
	defer f.Close()
	b, err := io.ReadAll(io.LimitReader(f, 1_000_000))
	if err != nil {
		return nil, err
	}
	var vars map[string]interface{}
	if err := json.Unmarshal(b, &vars); err != nil {
		return nil, errors.Wrap(err, "json.Unmarshal")
	}
	return vars, nil
}

func (p *Plugin) loadVariablesFromPluginMetadata() (map[string]interface{}, error) {
	// read the plugin metadata for default values
	pluginFile, err := os.Open(p.Command)
	if err != nil {
		return nil, errors.Wrap(err, "open plugin source")
	}
	defer pluginFile.Close()
	pluginFileB, err := io.ReadAll(io.LimitReader(pluginFile, 1_000_000))
	if err != nil {
		return nil, errors.Wrap(err, "read plugin source")
	}
	pluginMetadata, err := metadata.Parse(metadata.DebugFunc(p.Debugf), p.CleanFilename(), string(pluginFileB))
	if err != nil {
		return nil, errors.Wrap(err, "metadata.Parse")
	}
	vars := make(map[string]interface{})
	for _, pluginVar := range pluginMetadata.Vars {
		if pluginVar.Default == "" {
			// skip values with no default
			continue
		}
		vars[pluginVar.Name] = pluginVar.DefaultValue()
	}

View on GitHub (pinned to d624239058)

Solutions

  1. Verify the path in p.Command exists and is readable: `ls -l <path>`; reinstall the plugin if missing.
  2. Restore read/execute permissions on the plugin file (chmod +rx).
  3. Update or remove the stale plugin entry so xbar stops referencing the old path.
  4. Refresh the plugin list in xbar (refresh menu) so p.Command is re-resolved from the actual installed location.

Example fix

// before
pluginFile, err := os.Open(p.Command)
if err != nil {
	return nil, errors.Wrap(err, "open plugin source")
}
// after — guard at call site before loading vars
if _, err := os.Stat(p.Command); err != nil {
	return nil, nil // plugin gone; no defaults to load
}
pluginFile, err := os.Open(p.Command)
if err != nil {
	return nil, errors.Wrap(err, "open plugin source")
}
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(p.Command)
if err != nil {
	log.Printf("plugin source %s missing: %v", p.Command, err)
} else if info.IsDir() {
	log.Printf("plugin source %s is a directory", p.Command)
} else if info.Mode().Perm()&0444 == 0 {
	log.Printf("plugin source %s is not readable", p.Command)
}

Try / catch

if _, err := os.Stat(p.Command); err != nil {
	log.Printf("skipping plugin: source not found: %v", err)
	return nil // do not attempt to run or load vars
}
if err := p.run(); err != nil {
	if strings.Contains(err.Error(), "open plugin source") {
		log.Printf("plugin source unreadable, reinstall the plugin: %+v", err)
	}
}

Prevention

When it happens

Trigger: The plugin binary/script was deleted, renamed, or moved after its variables were configured; p.Command contains a stale absolute path (plugin dir moved, e.g. ~/Library/Application Support/xbar changed); permission denied on the executable; running with a working directory where a relative p.Command no longer resolves.

Common situations: User updates a plugin (file replaced/removed) while xbar still holds the old path; plugin installed from another user's home directory lacks read permission; plugin uninstalled but xbar tries to rebuild env vars from a stale entry.

Related errors


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