{"record":{"id":"457f81d7d6e5c022","repo":"kovidgoyal/kitty","slug":"layout-action-must-have-at-least-one-argument","errorCode":null,"errorMessage":"layout_action must have at least one argument","messagePattern":"layout_action must have at least one argument","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"kitty/options/utils.py","lineNumber":420,"sourceCode":"@func_with_args('disable_ligatures_in')\ndef disable_ligatures_in(func: str, rest: str) -> FuncArgsType:\n    parts = rest.split(maxsplit=1)\n    if len(parts) == 1:\n        where, strategy = 'active', parts[0]\n    else:\n        where, strategy = parts\n    if where not in ('active', 'all', 'tab'):\n        raise ValueError(f'{where} is not a valid set of windows to disable ligatures in')\n    if strategy not in ('never', 'always', 'cursor'):\n        raise ValueError(f'{strategy} is not a valid disable ligatures strategy')\n    return func, [where, strategy]\n\n\n@func_with_args('layout_action')\ndef layout_action(func: str, rest: str) -> FuncArgsType:\n    parts = rest.split(maxsplit=1)\n    if not parts:\n        raise ValueError('layout_action must have at least one argument')\n    return func, [parts[0], tuple(parts[1:])]\n\n\ndef parse_marker_spec(ftype: str, parts: Sequence[str]) -> tuple[str, str | tuple[tuple[int, str], ...], int]:\n    flags = re.UNICODE\n    if ftype in ('text', 'itext', 'regex', 'iregex'):\n        if ftype.startswith('i'):\n            flags |= re.IGNORECASE\n        if not parts or len(parts) % 2 != 0:\n            raise ValueError('Mark group number and text/regex are not specified in pairs: {}'.format(' '.join(parts)))\n        ans = []\n        for i in range(0, len(parts), 2):\n            try:\n                color = max(1, min(int(parts[i]), 3))\n            except Exception:\n                raise ValueError(f'Mark group in marker specification is not an integer: {parts[i]}')\n            sspec = parts[i + 1]\n            if 'regex' not in ftype:","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kitty/options/utils.py#L402-L438","documentation":"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.","triggerScenarios":"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.","commonSituations":"Truncated map lines from hand-editing; scripts calling kitten @action layout_action with no payload; whitespace-only arguments collapsing to empty after parsing.","solutions":["Provide at least the layout action name, e.g. `map ctrl+l layout_action toggle`","For remote control, pass a non-empty action string: kitty @action layout_action <name> [args...]","Check the map line was not truncated"],"exampleFix":"# before\nmap ctrl+l layout_action\n# after\nmap ctrl+l layout_action toggle","handlingStrategy":"validation","validationCode":"parts = rest.split(maxsplit=1)\nif not parts or not parts[0].strip():\n    raise SystemExit('layout_action needs an action name')","typeGuard":"def has_layout_action_arg(rest: str) -> bool:\n    return bool(rest.split(maxsplit=1))","tryCatchPattern":null,"preventionTips":["Always specify the layout action name in map lines","Validate script-built commands are non-empty"],"tags":["kitty","config","layout","action-args"],"backgroundTag":"missing-required-argument","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}