jesseduffield/lazygit · error

expected a string or a sequence of strings for keybinding, g

Error message

expected a string or a sequence of strings for keybinding, got %v

What it means

Thrown while unmarshalling a user-config keybinding in pkg/config/keybinding.go. The custom Keybinding type accepts either a plain YAML string or a sequence of strings; any other YAML node kind (map, bool, number written unquoted, null) reaches the default branch and is rejected with the offending node's tag. This is lazygit's config parser enforcing that every keybinding normalizes to a []string of real key names.

Source

Thrown at pkg/config/keybinding.go:34

// written in YAML/JSON as either a single scalar string or as a sequence of
// strings.
type Keybinding []string

func (k *Keybinding) UnmarshalYAML(node *yaml.Node) error {
	var ss []string
	switch node.Kind {
	case yaml.ScalarNode:
		var s string
		if err := node.Decode(&s); err != nil {
			return err
		}
		ss = []string{s}
	case yaml.SequenceNode:
		if err := node.Decode(&ss); err != nil {
			return err
		}
	default:
		return fmt.Errorf("expected a string or a sequence of strings for keybinding, got %v", node.Tag)
	}
	// Drop empty and <disabled> entries so clients never have to special-case
	// them: an empty Keybinding means "no key bound", a non-empty one is
	// guaranteed to contain only real keys.
	*k = lo.Filter(ss, func(s string, _ int) bool {
		return s != "" && s != "<disabled>"
	})
	return nil
}

func (k Keybinding) MarshalYAML() (any, error) {
	if len(k) == 1 {
		return k[0], nil
	}
	// Render multi-key bindings in flow style (`[a, b]`) rather than the default
	// block style, which is more compact and reads better in the generated docs.
	node := &yaml.Node{
		Kind:  yaml.SequenceNode,

View on GitHub (pinned to c477a2959b)

Solutions

  1. Open the user config file and change the offending keybinding to a single quoted string (e.g. `quit: 'q'`) or a YAML list of strings (`quit: [ctrl-q, q]`).
  2. Quote any keybinding that looks like a number, bool, or null (`'1'`, `'true'`, `'~'`).
  3. Check the line/column reported in the accompanying YAML error to find which key triggered the decode.
  4. Restart lazygit to confirm the config parses.

Example fix

# before (user config.yml)
quit: 5

# after
quit: '5'
Defensive patterns

Strategy: validation

Validate before calling

// Before yaml.Unmarshal into the config, assert every keybinding node is a string or sequence:
func assertKeybindingNode(path string, node *yaml.Node) error {
	if node.Kind != yaml.ScalarNode && node.Kind != yaml.SequenceNode {
		return fmt.Errorf("%s: expected string or list of strings, got %v", path, node.Tag)
	}
	return nil
}

Prevention

When it happens

Trigger: Writing `quit: 5` or `quit: true` (unquoted scalar decoded as int/bool tag), `quit: {key: q}` (mapping node), or `quit:` with a null value in the YAML user config, then starting lazygit (or running any code path that yaml-decodes into the Keybinding type).

Common situations: Users copy-pasting YAML from chat/wiki where quotes got stripped; using a bare number as a key name (e.g. `switchTab: 1` instead of `switchTab: '1'`); indentation mistakes turning a value into a nested map; switching from a string value to a structured form that the schema never supported.

Related errors


AI-assisted analysis of jesseduffield/lazygit@c477a2959b (2026-08-15). Data as JSON: /api/errors/85919f3d6f90b669. Report an issue: GitHub.