kovidgoyal/kitty · error · ValueError
Native key codes not allowed in send_key: {human_key}
Error message
Native key codes not allowed in send_key: {human_key} What it means
Window.send_key() parses each human-readable key with parse_shortcut() and refuses shortcuts whose key is a native key code (sk.is_native). send_key synthesizes GLFW key events, so platform-native codes cannot be mapped; use symbolic key names instead. The check happens per argument before any events are queued.
Source
Thrown at kitty/window.py:1247
Note that the key will be sent only if the current keyboard mode of the program running in the terminal supports it.
Both key press and key release are sent. First presses for all specified keys and then releases in reverse order.
To send a pattern of press and release for multiple keys use the :ac:`combine` action. For example::
map f1 send_key ctrl+x alt+y
map f1 combine : send_key ctrl+x : send_key alt+y
""",
)
def send_key(self, *args: str) -> bool:
from .options.utils import parse_shortcut
km = get_options().kitty_mod
passthrough = True
events = []
prev = ''
for human_key in args:
sk = parse_shortcut(human_key)
if sk.is_native:
raise ValueError(f'Native key codes not allowed in send_key: {human_key}')
sk = sk.resolve_kitty_mod(km)
events.append(KeyEvent(key=sk.key, mods=sk.mods, action=GLFW_REPEAT if human_key == prev else GLFW_PRESS))
prev = human_key
scroll_needed = False
for ev in events + [KeyEvent(key=x.key, mods=x.mods, action=GLFW_RELEASE) for x in reversed(events)]:
enc = self.encoded_key(ev)
if enc:
self.write_to_child(enc)
if ev.action != GLFW_RELEASE and not is_modifier_key(ev.key):
scroll_needed = True
passthrough = False
if scroll_needed:
self.scroll_end()
return passthrough
def send_key_sequence(self, *keys: KeyEvent, synthesize_release_events: bool = True) -> None:
for key in keys:
enc = self.encoded_key(key)View on GitHub (pinned to 6d5d0c4406)
Solutions
- Use symbolic names: send_key('ctrl+c'), send_key('enter'), send_key('f1')
- If you only need text input, use send_text / @ send-text which doesn't parse keys
- Find valid names via kitten show-key
Example fix
# before
window.send_key('native:65')
# after
window.send_key('space') Defensive patterns
Strategy: validation
Validate before calling
from kitty.key_encoding import parse_shortcut
sk = parse_shortcut(human_key)
if sk.is_native:
raise ValueError(f'use a symbolic key name, not {human_key}') Type guard
def is_symbolic_key(human_key: str) -> bool:
from kitty.key_encoding import parse_shortcut
return not parse_shortcut(human_key).is_native Try / catch
try:
window.send_key(*keys)
except ValueError as e:
if 'Native key codes' in str(e):
window.send_text(' '.join(keys)) # fallback: text input
else:
raise Prevention
- Whitelist symbolic key names in remote-control scripts
- Use send_text for literal text and send_key only for named keys/symbols
When it happens
Trigger: Calling send_key('native:0x20') or any shortcut string whose key part resolves to a native code rather than a GLFW/symbolic name, e.g. send_key('native_key_here').
Common situations: Feeding platform scan codes or keysym numbers obtained from other tools into send_key; remote-control scripts (kitten @ send-key) passing machine-level codes; confusing send_key with the escape-code based send_text.
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/348dfd108baac55c.
Report an issue: GitHub.