{"record":{"id":"28a7e370d5c7c88c","repo":"kovidgoyal/kitty","slug":"the-menu-entry-name-in-val-must-end-with-a-doubl","errorCode":null,"errorMessage":"The menu entry name in {val} must end with a double quote","messagePattern":"The menu entry name in (.+?) must end with a double quote","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"kitty/options/utils.py","lineNumber":1157,"sourceCode":"\ndef store_multiple(val: str, current_val: Container[str]) -> Iterable[tuple[str, str]]:\n    val = val.strip()\n    if val not in current_val:\n        yield val, val\n\n\ndef menu_map(val: str, current_val: Container[str]) -> Iterable[tuple[tuple[str, ...], str]]:\n    parts = val.split(maxsplit=1)\n    if len(parts) != 2:\n        raise ValueError(f'Ignoring invalid menu action: {val}')\n    if parts[0] != 'global':\n        raise ValueError(f'Unknown menu type: {parts[0]}. Known types: global')\n    start = 0\n    if parts[1].startswith('\"'):\n        start = 1\n        idx = parts[1].find('\"', 1)\n        if idx == -1:\n            raise ValueError(f'The menu entry name in {val} must end with a double quote')\n    else:\n        idx = parts[1].find(' ')\n        if idx == -1:\n            raise ValueError(f'The menu entry {val} must have an action')\n    location = ('global',) + tuple(parts[1][start:idx].split('::'))\n    yield location, parts[1][idx + 1 :].lstrip()\n\n\nallowed_shell_integration_values = frozenset({'enabled', 'disabled', 'no-rc', 'no-cursor', 'no-title', 'no-prompt-mark', 'no-complete', 'no-cwd', 'no-sudo'})\n\n\ndef shell_integration(x: str) -> frozenset[str]:\n    q = frozenset(x.lower().split())\n    if not q.issubset(allowed_shell_integration_values):\n        log_error(f'Invalid shell integration options: {q - allowed_shell_integration_values}, ignoring')\n        return q & allowed_shell_integration_values or frozenset({'invalid'})\n    return q\n","sourceCodeStart":1139,"sourceCodeEnd":1175,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kitty/options/utils.py#L1139-L1175","documentation":"When a menu entry name is quoted (starts with '\"'), menu_map requires a matching closing double quote; if none is found in the remaining string this ValueError is raised.","triggerScenarios":"menu global \"My Item launch nvim — opening quote with no closing quote before the action.","commonSituations":"Unbalanced quotes when menu names contain spaces; smart-quote substitution from rich-text paste.","solutions":["Close the quoted name: menu global \"My Item\" launch nvim","Alternatively omit quotes if the name has no spaces"],"exampleFix":"# before\nmenu global \"My Item launch nvim\n# after\nmenu global \"My Item\" launch nvim","handlingStrategy":"validation","validationCode":"def valid_menu_name(rest: str) -> bool:\n    if rest.startswith('\"'):\n        return rest.find('\"', 1) != -1\n    return ' ' in rest","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair opening and closing double quotes","Avoid smart quotes pasted from rich text"],"tags":["kitty","config","menus","quoting"],"backgroundTag":"config-value-validation-failed","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}