derailed/k9s · error

duplicate input name %q

Error message

duplicate input name %q

What it means

Returned by Plugin.Validate (internal/config/plugin.go:87) when two entries in a plugin's inputs list share the same name. Input names key the prompt form and the value substitution map, so duplicates are ambiguous and rejected. Via Plugins.load this surfaces as 'plugin validation failed for <file>: duplicate input name ...' and the whole plugin file is skipped — the plugin simply does not register.

Source

Thrown at internal/config/plugin.go:87

func (p Plugin) String() string {
	return fmt.Sprintf("[%s] %s(%s)", p.ShortCut, p.Command, strings.Join(p.Args, " "))
}

// ShouldConfirm returns whether the plugin should show a confirmation dialog.
// Defaults to true when inputs are defined, false otherwise.
func (p *Plugin) ShouldConfirm() bool {
	if p.Confirm != nil {
		return *p.Confirm
	}
	return len(p.Inputs) > 0
}

// Validate checks the plugin configuration for errors.
func (p *Plugin) Validate() error {
	seen := make(map[string]struct{}, len(p.Inputs))
	for _, input := range p.Inputs {
		if _, ok := seen[input.Name]; ok {
			return fmt.Errorf("duplicate input name %q", input.Name)
		}
		seen[input.Name] = struct{}{}

		if input.Default == "" {
			continue
		}

		switch input.Type {
		case InputTypeDropdown:
			if !slices.Contains(input.Options, input.Default) {
				return fmt.Errorf("default value %q for input %q is not a valid option", input.Default, input.Name)
			}
		case InputTypeBool:
			if input.Default != "true" && input.Default != "false" {
				return fmt.Errorf("default value %q for bool input %q must be \"true\" or \"false\"", input.Default, input.Name)
			}
		case InputTypeNumber:
			if _, err := strconv.ParseFloat(input.Default, 64); err != nil {

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Open the plugin file named in the error and make each input's name unique (e.g. namespace, resource_name)
  2. If the duplicate was intentional duplication of behavior, merge the two inputs into one
  3. Re-run k9s and confirm the plugin appears in :plugins

Example fix

# before
plugins:
  myplug:
    ... 
    inputs:
      - name: ns
        type: string
      - name: ns        # duplicate
        type: string

# after
      - name: ns
        type: string
      - name: resource
        type: string
Defensive patterns

Strategy: validation

Validate before calling

func inputNamesUnique(p Plugin) bool {
	seen := make(map[string]struct{}, len(p.Inputs))
	for _, in := range p.Inputs {
		if _, dup := seen[in.Name]; dup {
			return false
		}
		seen[in.Name] = struct{}{}
	}
	return true
}

Try / catch

if err := plugin.Validate(); err != nil {
	if strings.Contains(err.Error(), "duplicate input name") {
		// skip this plugin file, keep loading others; surface the name in UI
	}
}

Prevention

When it happens

Trigger: Defining a plugin with inputs: [{name: ns, ...}, {name: ns, ...}] — typically copy-paste of an input block where the second name was not updated.

Common situations: Building multi-prompt plugins (namespace + resource name) by duplicating YAML blocks; merging plugin definitions from examples; refactoring inputs and leaving a stale duplicate behind.

Related errors


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