hasura/graphql-engine · error
failed to open index file: %w
Error message
failed to open index file: %w
What it means
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.
Source
Thrown at cli/plugins/scanner.go:154
c.Logger.Debugf("failed to append version %s for plugin %s: %v", p.Version, p.Name, err)
continue
}
}
return ps
}
// ReadPluginFromFile loads a file from the FS. When plugin file not found, it
// returns an error that can be checked with stderrors.Is(err, fs.ErrNotExist).
func (c *Config) ReadPluginFromFile(path string) (Plugin, error) {
var op errors.Op = "plugins.Config.ReadPluginFromFile"
f, err := os.Open(path)
if stderrors.Is(err, fs.ErrNotExist) {
return Plugin{}, errors.E(op, err)
} else if err != nil {
return Plugin{}, errors.E(op, fmt.Errorf("failed to open index file: %w", err))
}
defer f.Close()
var plugin Plugin
b, err := io.ReadAll(f)
if err != nil {
return plugin, errors.E(op, err)
}
err = yaml.Unmarshal(b, &plugin)
if err != nil {
return plugin, errors.E(op, fmt.Errorf("failed to decode plugin manifest: %w", err))
}
plugin.ParseVersion()
err = plugin.ValidatePlugin(plugin.Name)View on GitHub (pinned to 724551b9ae)
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
Example fix
# before mycli plugin list # Error: failed to open index file: open ~/.mycli/plugins/index/foo.yaml: permission denied # after chmod 644 ~/.mycli/plugins/index/*.yaml && mycli plugin list
Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := os.Stat(manifestPath); err != nil { /* missing: not installed */ }
if info, err := os.Stat(manifestPath); err == nil && info.Mode().Perm()&0o400 == 0 { /* unreadable */ } Try / catch
p, err := cfg.ReadPluginFromFile(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) { /* treat as not installed */ }
// otherwise: permission or fd exhaustion — inspect wrapped error
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- could not remove plugin directory %q: %w
- could not create staging dir %q: %w
- write plugin receipt %q: %w
- failed to ensure create directory %q: %w
- failed to remove old symlink: %w
AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28).
Data as JSON: /api/errors/21fcc6d5df060c5f.
Report an issue: GitHub.