matryer/xbar · error
ReadDir
Error message
ReadDir
What it means
Returned by GetInstalledPlugins when ioutil/os.ReadDir on the plugins directory fails with an error other than NotExist (which is treated as 'no plugins installed' and returns nil, nil). The raw directory-read error is wrapped with the label 'ReadDir'. It means the plugins directory exists but could not be listed.
Source
Thrown at pkg/plugins/installed_plugins.go:62
if !enabled && IsPluginEnabled(installedPluginPath) {
newFullPluginPath := fullPluginPath + disabledPluginExtension
newInstalledPluginPath := installedPluginPath + disabledPluginExtension
err := os.Rename(fullPluginPath, newFullPluginPath)
return newInstalledPluginPath, err
}
return installedPluginPath, nil
}
// GetInstalledPlugins gets the installed fplugins from the pluginDirectory.
func GetInstalledPlugins(pluginDirectory string) ([]InstalledPlugin, error) {
files, err := ioutil.ReadDir(pluginDirectory)
if err != nil {
if os.IsNotExist(err) {
// no plugins directory - so no installed plugins
// but not an error
return nil, nil
}
return nil, errors.Wrap(err, "ReadDir")
}
var installedPlugins []InstalledPlugin
for _, file := range files {
if file.IsDir() {
continue
}
if strings.HasPrefix(file.Name(), ".") {
continue
}
if strings.HasSuffix(file.Name(), variableJSONFileExt) {
// ignore variable payload files
continue
}
enabled := !strings.HasSuffix(file.Name(), disabledPluginExtension)
name := file.Name()
installedPlugin := InstalledPlugin{
Name: name,
Path: file.Name(),View on GitHub (pinned to d624239058)
Solutions
- Fix permissions on the plugin directory so the current user can read it (chmod a+rX / chown).
- Verify the PluginDir path: if an intermediate component is a file, remove or correct the configuration.
- If the directory should not exist, the error path was NotExist — check for a stale file at the path and delete it, then retry.
Example fix
// before
dir := "/var/lib/upterm/plugins" // root-owned
pls, err := plugins.GetInstalledPlugins(dir)
// after
if fi, err := os.Stat(dir); err == nil && fi.Mode().Perm()&0444 == 0 {
os.Chmod(dir, 0755)
}
pls, err := plugins.GetInstalledPlugins(dir) Defensive patterns
Strategy: try-catch
Validate before calling
func readableDir(dir string) error {
fi, err := os.Stat(dir)
if os.IsNotExist(err) { return nil } // treated as no plugins
if err != nil { return err }
if !fi.IsDir() { return fmt.Errorf("%s is not a directory", dir) }
f, err := os.Open(dir)
if err != nil { return err }
f.Close()
return nil
} Try / catch
pls, err := plugins.GetInstalledPlugins(dir)
if err != nil && strings.Contains(err.Error(), "ReadDir") {
var pe *os.PathError
if errors.As(err, &pe) && os.IsPermission(pe) {
log.Fatalf("cannot read plugin dir %s: fix permissions", pe.Path)
}
return err
} Prevention
- Install and read plugins as the same user to avoid ownership mismatches.
- Avoid sudo-installing plugins into a user-owned directory.
- Verify PluginDir is a directory, not a file, at startup.
- Handle 'not exist' as empty (the library already does) — only fix real read errors.
When it happens
Trigger: Calling GetInstalledPlugins when the plugin directory exists but cannot be read: permission denied on the directory, path component is a file, or an I/O error on the filesystem.
Common situations: Plugin dir owned by another user after a sudo install; PluginDir env/config pointing at a path whose component is a regular file; corrupted or failing mount.
Related errors
- create directory %s for plugin
- create plugin file %s
- set executable permission on plugin entry point
- WriteFile
- Open
AI-assisted analysis of matryer/xbar@d624239058 (2026-09-02).
Data as JSON: /api/errors/596db7bef3b93370.
Report an issue: GitHub.