derailed/k9s · error

plugin validation failed for %s: %w

Error message

plugin validation failed for %s: %w

What it means

Plugins.load (internal/config/plugin.go:158-165) first runs the plugin file through data.JSONValidator.ValidatePlugins, which validates the document against k9s's bundled JSON schemas and detects which of the three supported shapes it is (plugin / plugins map / plugins list). This error wraps that schema failure with the offending file path; the raw validation detail is also logged as a slog.Warn with slogs.Path and slogs.Error.

Source

Thrown at internal/config/plugin.go:164

	return errs
}

func (p *Plugins) load(path string) error {
	if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {
		return nil
	}
	bb, err := os.ReadFile(path)
	if err != nil {
		return err
	}
	scheme, err := data.JSONValidator.ValidatePlugins(bb)
	if err != nil {
		slog.Warn("Plugin schema validation failed",
			slogs.Path, path,
			slogs.Error, err,
		)
		return fmt.Errorf("plugin validation failed for %s: %w", path, err)
	}

	d := yaml.NewDecoder(bytes.NewReader(bb))
	d.KnownFields(true)

	switch scheme {
	case json.PluginSchema:
		var o Plugin
		if err := yaml.Unmarshal(bb, &o); err != nil {
			return fmt.Errorf("plugin unmarshal failed for %s: %w", path, err)
		}
		if err := o.Validate(); err != nil {
			return fmt.Errorf("plugin validation failed for %s: %w", path, err)
		}
		p.Plugins[strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))] = o
	case json.PluginsSchema:
		var oo Plugins
		if err := yaml.Unmarshal(bb, &oo); err != nil {

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Run k9s from a terminal and read the slog.Warn line immediately preceding the returned error - it carries the exact schema violation
  2. Fix the file so it matches one of the three supported shapes: a single plugin object, a `plugins:` map keyed by name, or a `plugins:` list
  3. Correct field names/casing (shortCut, command, description, scopes) against the bundled schema
  4. If the file is not meant for k9s, remove it from the plugins directory ($XDG_CONFIG_HOME/k9s/plugins, XDG data dirs, or the context config path)

Example fix

# before (unknown key, missing shortCut)
shortcut: e
description: edit
command: vim
# after
shortCut: e
description: edit
command: vim
Defensive patterns

Strategy: validation

Validate before calling

// Smoke-test a plugin file before dropping it into k9s's config dirs:
// it must parse as YAML and carry only known top-level keys.
var knownKeys = map[string]bool{"shortCut":true,"description":true,"command":true,"scopes":true,"args":true,"override":true,"pipes":true,"confirm":true,"background":true,"dangerous":true,"overwriteOutput":true,"inputs":true,"plugins":true}

func LintPluginFile(path string) error {
	b, err := os.ReadFile(path)
	if err != nil { return err }
	var m map[string]any
	if err := yaml.Unmarshal(b, &m); err != nil { return err }
	for k := range m {
		if !knownKeys[k] { return fmt.Errorf("unknown key %q in %s", k, path) }
	}
	return nil
}

Prevention

When it happens

Trigger: A plugin file whose top-level keys do not match any supported schema: unknown fields, missing required fields (shortCut, command, description), wrong types (scopes not a string list), or a document that mixes the single-plugin and map forms. It aborts before any yaml.Unmarshal of the plugin body runs.

Common situations: Upgrading k9s where the plugin schema gained/renamed required fields; typos in top-level keys (e.g. shortcut vs shortCut); using a plugin written for another tool or an older k9s version; extra XDG data-dir plugin files shipping with a distribution.

Related errors


AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15). Data as JSON: /api/errors/7fdfb0c29e3a087a. Report an issue: GitHub.