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

  1. ls -l the manifest file from the error path and fix mode/ownership (chmod 644 / chown)
  2. Raise the file-descriptor limit (ulimit -n) if you see 'too many open files' in the wrapped error
  3. 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

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


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/21fcc6d5df060c5f. Report an issue: GitHub.