{"record":{"id":"596db7bef3b93370","repo":"matryer/xbar","slug":"readdir","errorCode":null,"errorMessage":"ReadDir","messagePattern":"ReadDir","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/plugins/installed_plugins.go","lineNumber":62,"sourceCode":"\tif !enabled && IsPluginEnabled(installedPluginPath) {\n\t\tnewFullPluginPath := fullPluginPath + disabledPluginExtension\n\t\tnewInstalledPluginPath := installedPluginPath + disabledPluginExtension\n\t\terr := os.Rename(fullPluginPath, newFullPluginPath)\n\t\treturn newInstalledPluginPath, err\n\t}\n\treturn installedPluginPath, nil\n}\n\n// GetInstalledPlugins gets the installed fplugins from the pluginDirectory.\nfunc GetInstalledPlugins(pluginDirectory string) ([]InstalledPlugin, error) {\n\tfiles, err := ioutil.ReadDir(pluginDirectory)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\t// no plugins directory - so no installed plugins\n\t\t\t// but not an error\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, errors.Wrap(err, \"ReadDir\")\n\t}\n\tvar installedPlugins []InstalledPlugin\n\tfor _, file := range files {\n\t\tif file.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\tif strings.HasPrefix(file.Name(), \".\") {\n\t\t\tcontinue\n\t\t}\n\t\tif strings.HasSuffix(file.Name(), variableJSONFileExt) {\n\t\t\t// ignore variable payload files\n\t\t\tcontinue\n\t\t}\n\t\tenabled := !strings.HasSuffix(file.Name(), disabledPluginExtension)\n\t\tname := file.Name()\n\t\tinstalledPlugin := InstalledPlugin{\n\t\t\tName:    name,\n\t\t\tPath:    file.Name(),","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/matryer/xbar/blob/d624239058997c80118eaebe2e7f8331b3c765e0/pkg/plugins/installed_plugins.go#L44-L80","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ndir := \"/var/lib/upterm/plugins\" // root-owned\npls, err := plugins.GetInstalledPlugins(dir)\n// after\nif fi, err := os.Stat(dir); err == nil && fi.Mode().Perm()&0444 == 0 {\n    os.Chmod(dir, 0755)\n}\npls, err := plugins.GetInstalledPlugins(dir)","handlingStrategy":"try-catch","validationCode":"func readableDir(dir string) error {\n    fi, err := os.Stat(dir)\n    if os.IsNotExist(err) { return nil } // treated as no plugins\n    if err != nil { return err }\n    if !fi.IsDir() { return fmt.Errorf(\"%s is not a directory\", dir) }\n    f, err := os.Open(dir)\n    if err != nil { return err }\n    f.Close()\n    return nil\n}","typeGuard":null,"tryCatchPattern":"pls, err := plugins.GetInstalledPlugins(dir)\nif err != nil && strings.Contains(err.Error(), \"ReadDir\") {\n    var pe *os.PathError\n    if errors.As(err, &pe) && os.IsPermission(pe) {\n        log.Fatalf(\"cannot read plugin dir %s: fix permissions\", pe.Path)\n    }\n    return err\n}","preventionTips":["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."],"tags":["go","filesystem","readdir","permissions","plugins"],"backgroundTag":"readdir-permission-denied","analyzedSha":"d624239058997c80118eaebe2e7f8331b3c765e0","analyzedAt":"2026-09-02T22:38:22.007Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}