kovidgoyal/kitty · warning
Ignoring invalid remap_modifiers "{val}": {msg}
Error message
Ignoring invalid remap_modifiers "{val}": {msg} What it means
The remap_modifiers option value failed validation; kitty logs the specific reason and disables the entire remapping (returns {}). Example reasons: not colon-separated pairs, unknown modifier names, or mapping a non-remappable modifier.
Source
Thrown at kitty/options/utils.py:541
def to_modifiers(val: str) -> int:
return parse_mods(val.split('+'), val) or 0
def remap_modifiers(val: str) -> dict[int, int]:
# Only the real modifiers may be remapped. parse_mods() also accepts
# kitty_mod (a parse-time placeholder resolved out of keymaps before any key
# event exists) and the lock modifiers, neither of which can be meaningfully
# carried on an event, so they are rejected here rather than silently
# mangling events later.
ans = {}
if not val:
return ans
remappable = (
defines.GLFW_MOD_SHIFT | defines.GLFW_MOD_ALT | defines.GLFW_MOD_CONTROL | defines.GLFW_MOD_SUPER | defines.GLFW_MOD_HYPER | defines.GLFW_MOD_META
)
def bad(msg: str) -> None:
log_error(f'Ignoring invalid remap_modifiers "{val}": {msg}')
for token in val.split():
parts = token.split(':', 1)
if len(parts) != 2:
bad('must be two modifier names separated by a colon')
return {}
# parse_mods() returns None both for an unknown name (already logged) and for
# "none" (deliberately not logged), so check the names before trusting it
for part in parts:
for name in part.split('+'):
if name.upper() in ('NONE', ''):
bad('none is not a modifier')
return {}
src = parse_mods(parts[0].split('+'), val)
dest = parse_mods(parts[1].split('+'), val)
if src is None or dest is None:
return {} # parse_mods() has already logged the unknown modifier name
if src & ~remappable or dest & ~remappable:View on GitHub (pinned to 6d5d0c4406)
Solutions
- Use pairs of remappable modifier names separated by colons: `remap_modifiers alt:ctrl shift:alt`
- Only remap shift, alt, ctrl, super, hyper, meta; for caps lock use the OS keyboard settings or kitty's modify_other_keys related options instead
- Remove stray tokens that aren't name:name pairs
Example fix
# before remap_modifiers caps_lock:ctrl # after remap_modifiers alt:ctrl
Defensive patterns
Strategy: validation
Validate before calling
val = 'alt:ctrl'
tokens = val.split()
ok = all(len(t.split(':',1)) == 2 for t in tokens) and all(
p in ('shift','alt','ctrl','super','hyper','meta') for t in tokens for p in t.split(':',1)) Prevention
- remap_modifiers accepts only colon-separated pairs of shift/alt/ctrl/super/hyper/meta
- One malformed token disables the entire option
- Use OS-level remapping for keys like caps lock
When it happens
Trigger: Setting `remap_modifiers ctrl:alt extra` (extra token lacks a colon), or `remap_modifiers caps:ctrl` where the modifier isn't in the remappable mask (shift/alt/ctrl/super/hyper/meta).
Common situations: Trying to remap caps lock or other keys not in kitty's remappable set; malformed colon syntax; assuming arbitrary key names are remappable.
Related errors
- Shortcut: {sc} has unknown modifier, ignoring
- Invalid shortcut
- Unknown signal: {rest} ignoring
- Invalid change_font_size specification: {rest}, treating it
- clear_terminal needs two arguments, using defaults
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/ba9dacc1e249cfb2.
Report an issue: GitHub.