kovidgoyal/kitty · error · ValueError

layout_action must have at least one argument

Error message

layout_action must have at least one argument

What it means

layout_action is a func_with_args handler for the layout_action remote-control/map action. rest.split(maxsplit=1) on an already-split string never yields an empty list in practice, so the 'must have at least one argument' branch guards against an empty action name; it returns the layout name plus a tuple of remaining args.

Source

Thrown at kitty/options/utils.py:420

@func_with_args('disable_ligatures_in')
def disable_ligatures_in(func: str, rest: str) -> FuncArgsType:
    parts = rest.split(maxsplit=1)
    if len(parts) == 1:
        where, strategy = 'active', parts[0]
    else:
        where, strategy = parts
    if where not in ('active', 'all', 'tab'):
        raise ValueError(f'{where} is not a valid set of windows to disable ligatures in')
    if strategy not in ('never', 'always', 'cursor'):
        raise ValueError(f'{strategy} is not a valid disable ligatures strategy')
    return func, [where, strategy]


@func_with_args('layout_action')
def layout_action(func: str, rest: str) -> FuncArgsType:
    parts = rest.split(maxsplit=1)
    if not parts:
        raise ValueError('layout_action must have at least one argument')
    return func, [parts[0], tuple(parts[1:])]


def parse_marker_spec(ftype: str, parts: Sequence[str]) -> tuple[str, str | tuple[tuple[int, str], ...], int]:
    flags = re.UNICODE
    if ftype in ('text', 'itext', 'regex', 'iregex'):
        if ftype.startswith('i'):
            flags |= re.IGNORECASE
        if not parts or len(parts) % 2 != 0:
            raise ValueError('Mark group number and text/regex are not specified in pairs: {}'.format(' '.join(parts)))
        ans = []
        for i in range(0, len(parts), 2):
            try:
                color = max(1, min(int(parts[i]), 3))
            except Exception:
                raise ValueError(f'Mark group in marker specification is not an integer: {parts[i]}')
            sspec = parts[i + 1]
            if 'regex' not in ftype:

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Provide at least the layout action name, e.g. `map ctrl+l layout_action toggle`
  2. For remote control, pass a non-empty action string: kitty @action layout_action <name> [args...]
  3. Check the map line was not truncated

Example fix

# before
map ctrl+l layout_action
# after
map ctrl+l layout_action toggle
Defensive patterns

Strategy: validation

Validate before calling

parts = rest.split(maxsplit=1)
if not parts or not parts[0].strip():
    raise SystemExit('layout_action needs an action name')

Type guard

def has_layout_action_arg(rest: str) -> bool:
    return bool(rest.split(maxsplit=1))

Prevention

When it happens

Trigger: Invoking layout_action with no action name, e.g. a map line `map ctrl+l layout_action` (empty rest), or a remote-control call passing an empty string after the action keyword.

Common situations: Truncated map lines from hand-editing; scripts calling kitten @action layout_action with no payload; whitespace-only arguments collapsing to empty after parsing.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/457f81d7d6e5c022. Report an issue: GitHub.