{"record":{"id":"21fcc6d5df060c5f","repo":"hasura/graphql-engine","slug":"failed-to-open-index-file-w","errorCode":null,"errorMessage":"failed to open index file: %w","messagePattern":"failed to open index file: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/plugins/scanner.go","lineNumber":154,"sourceCode":"\t\t\tc.Logger.Debugf(\"failed to append version %s for plugin %s: %v\", p.Version, p.Name, err)\n\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn ps\n}\n\n// ReadPluginFromFile loads a file from the FS. When plugin file not found, it\n// returns an error that can be checked with stderrors.Is(err, fs.ErrNotExist).\nfunc (c *Config) ReadPluginFromFile(path string) (Plugin, error) {\n\tvar op errors.Op = \"plugins.Config.ReadPluginFromFile\"\n\n\tf, err := os.Open(path)\n\tif stderrors.Is(err, fs.ErrNotExist) {\n\t\treturn Plugin{}, errors.E(op, err)\n\t} else if err != nil {\n\t\treturn Plugin{}, errors.E(op, fmt.Errorf(\"failed to open index file: %w\", err))\n\t}\n\tdefer f.Close()\n\n\tvar plugin Plugin\n\n\tb, err := io.ReadAll(f)\n\tif err != nil {\n\t\treturn plugin, errors.E(op, err)\n\t}\n\n\terr = yaml.Unmarshal(b, &plugin)\n\tif err != nil {\n\t\treturn plugin, errors.E(op, fmt.Errorf(\"failed to decode plugin manifest: %w\", err))\n\t}\n\n\tplugin.ParseVersion()\n\n\terr = plugin.ValidatePlugin(plugin.Name)","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/cli/plugins/scanner.go#L136-L172","documentation":"ReadPluginFromFile opens a plugin manifest YAML file; a missing file (fs.ErrNotExist) is returned bare so callers can Is(err, os.ErrNotExist), but any other open failure — permission denied, too many open files, I/O error — gets wrapped in this message.","triggerScenarios":"Calling GetPlugin, LoadManifest, or LoadPlugins when a *.yaml manifest under the plugins index exists but cannot be opened: mode 000, owned by another user, or EMFILE when the process exhausted file descriptors.","commonSituations":"Manifest files created by root during a sudo-run install; ulimit -n exhausted by long-running processes that repeatedly read manifests; container read-only layers with restrictive modes.","solutions":["ls -l the manifest file from the error path and fix mode/ownership (chmod 644 / chown)","Raise the file-descriptor limit (ulimit -n) if you see 'too many open files' in the wrapped error","Delete stale unreadable manifests and reinstall the plugin to regenerate them"],"exampleFix":"# before\nmycli plugin list\n# Error: failed to open index file: open ~/.mycli/plugins/index/foo.yaml: permission denied\n\n# after\nchmod 644 ~/.mycli/plugins/index/*.yaml && mycli plugin list","handlingStrategy":"try-catch","validationCode":"if _, err := os.Stat(manifestPath); err != nil { /* missing: not installed */ }\nif info, err := os.Stat(manifestPath); err == nil && info.Mode().Perm()&0o400 == 0 { /* unreadable */ }","typeGuard":null,"tryCatchPattern":"p, err := cfg.ReadPluginFromFile(path)\nif err != nil {\n\tif errors.Is(err, os.ErrNotExist) { /* treat as not installed */ }\n\t// otherwise: permission or fd exhaustion — inspect wrapped error\n}","preventionTips":["Distinguish fs.ErrNotExist from other open errors using errors.Is","Raise ulimit -n in long-running processes that read many manifests","Keep manifest files mode 0644"],"tags":["plugins","filesystem","file-open","permissions"],"backgroundTag":"file-open-permission-denied","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}