{"record":{"id":"3488df0e004658b4","repo":"hasura/graphql-engine","slug":"failed-to-scan-plugins-in-index-directory-w","errorCode":null,"errorMessage":"failed to scan plugins in index directory: %w","messagePattern":"failed to scan plugins in index directory: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/plugins/scanner.go","lineNumber":69,"sourceCode":"\tif err != nil {\n\t\treturn nil, errors.E(op, err)\n\t}\n\n\treturn out, nil\n}\n\n// LoadPluginListFromFS will parse and retrieve all plugin files.\nfunc (c *Config) LoadPluginListFromFS(indexDir string) (Plugins, error) {\n\tvar op errors.Op = \"plugins.Config.LoadPluginListFromFS\"\n\n\tindexDir, err := filepath.EvalSymlinks(indexDir)\n\tif err != nil {\n\t\treturn nil, errors.E(op, err)\n\t}\n\n\tfiles, err := c.findPluginManifestFiles(indexDir)\n\tif err != nil {\n\t\treturn nil, errors.E(op, fmt.Errorf(\"failed to scan plugins in index directory: %w\", err))\n\t}\n\n\treturn c.LoadPlugins(files), nil\n}\n\n// LoadPluginByName loads a plugins index file by its name. When plugin\n// file not found, it returns an error that can be checked with stderrors.Is(err, fs.ErrNotExist).\nfunc (c *Config) LoadPluginByName(pluginName string) (*PluginVersions, error) {\n\tvar op errors.Op = \"plugins.Config.LoadPluginByName\"\n\n\tc.Logger.Debugf(\"loading plugin %s\", pluginName)\n\n\tif !IsSafePluginName(pluginName) {\n\t\treturn nil, errors.E(op, fmt.Errorf(\"plugin name %q not allowed\", pluginName))\n\t}\n\n\tfiles, err := c.findPluginManifestFiles(c.Paths.IndexPluginsPath())\n\tif err != nil {","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/cli/plugins/scanner.go#L51-L87","documentation":"LoadPluginListFromFS enumerates all plugin manifest files via findPluginManifestFiles before loading them; this error means that directory scan failed. It wraps the underlying filesystem error from walking the plugins index directory.","triggerScenarios":"Calling Config.ListPlugins when the plugins index directory cannot be read: it is a file instead of a directory, permissions deny traversal, or an I/O error occurs during the directory walk.","commonSituations":"Plugins index dir was replaced by a symlink to an unreachable location; directory permissions were tightened (chmod 700 by another user); NFS/network mount dropped mid-walk.","solutions":["Check permissions and reachability of Paths.IndexPluginsPath(): ls -la on the directory","If the directory is a broken symlink or a file, remove it and recreate as a directory","For network-mounted home dirs, verify the mount is healthy and retry"],"exampleFix":"# before\nmycli plugin list\n# Error: failed to scan plugins in index directory: ... permission denied\n\n# after\nsudo chown -R $(whoami) ~/.mycli/plugins && mycli plugin list","handlingStrategy":"validation","validationCode":"info, err := os.Stat(cfg.Paths.IndexPluginsPath())\nif err != nil || !info.IsDir() { /* recreate dir or abort with clear message */ }","typeGuard":null,"tryCatchPattern":"plugins, err := cfg.LoadPluginListFromFS()\nif err != nil {\n\tif strings.Contains(err.Error(), \"failed to scan plugins\") {\n\t\t// filesystem issue with index dir: surface a permissions hint\n\t}\n}","preventionTips":["Ensure the plugins index dir is a real writable directory","Avoid symlinking the plugins dir to removable/network mounts","Monitor permissions after sudo usage"],"tags":["plugins","filesystem","directory-scan"],"backgroundTag":"directory-scan-failed","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}