kovidgoyal/kitty · error
JSON payload of remote command is invalid, must be an object
Error message
JSON payload of remote command is invalid, must be an object with a version field
What it means
The remote-control JSON parsed successfully but is not an object containing a 'version' field, which every kitty RC command must have. The command is rejected before any handler runs.
Source
Thrown at kitty/remote_control.py:55
T = TypeVar('T')
if TYPE_CHECKING:
from .window import Window
def encode_response_for_peer(response: Any) -> bytes:
return b'\x1bP@kitty-cmd' + json.dumps(response).encode('utf-8') + b'\x1b\\'
def parse_cmd(serialized_cmd: memoryview, encryption_key: EllipticCurveKey) -> dict[str, Any]:
# See https://github.com/python/cpython/issues/74379 for why we cant use
# memoryview directly :((
try:
pcmd = json.loads(bytes(serialized_cmd))
except Exception:
log_error('Failed to parse JSON payload of remote command, ignoring it')
return {}
if not isinstance(pcmd, dict) or 'version' not in pcmd:
log_error('JSON payload of remote command is invalid, must be an object with a version field')
return {}
pcmd.pop('password', None)
if 'encrypted' in pcmd:
if pcmd.get('enc_proto', '1') != RC_ENCRYPTION_PROTOCOL_VERSION:
log_error(f'Ignoring encrypted rc command with unsupported protocol: {pcmd.get("enc_proto")}')
return {}
pubkey = pcmd.get('pubkey', '')
if not pubkey:
log_error('Ignoring encrypted rc command without a public key')
d = AES256GCMDecrypt(encryption_key.derive_secret(base64.b85decode(pubkey)), base64.b85decode(pcmd['iv']), base64.b85decode(pcmd['tag']))
data = d.add_data_to_be_decrypted(base64.b85decode(pcmd['encrypted']), True)
pcmd = json.loads(data)
if not isinstance(pcmd, dict) or 'version' not in pcmd:
return {}
delta = time_ns() - pcmd.pop('timestamp')
if abs(delta) > 5 * 60 * 1e9:
log_error(
f'Ignoring encrypted rc command with timestamp {delta / 1e9:.1f} seconds from now.'View on GitHub (pinned to 6d5d0c4406)
Solutions
- Send commands via 'kitten @<command>' or kitty/cli.py helpers so the version field is included
- If hand-rolling payloads, include "version": [major, minor] matching the RC API version
- Check for version skew between client and server kitty installs
Example fix
# before
echo '{"cmd":"send-text"}' | nc -U ~/.local/share/kitty/rc-socket
# after
kitten @send-text --match-tab title:mytab 'hello' Defensive patterns
Strategy: validation
Validate before calling
payload = {'version': [0, 28], 'cmd': 'send-text', ...}
assert isinstance(payload, dict) and 'version' in payload Type guard
def is_rc_dict(x) -> bool:
return isinstance(x, dict) and isinstance(x.get('version'), list) Prevention
- Use kitten @ commands instead of raw socket writes
- Always include the version field; check docs for the current RC API version
When it happens
Trigger: parse_cmd receives valid JSON that is a list, string, or an object lacking the 'version' key (e.g. hand-crafted socket message).
Common situations: Custom scripts writing directly to the kitty socket without using the kitten remote-control client format.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- This should be run as kitten icat
- This should be run as `kitten notify ...`
- Remote control not enabled, this kitten should be run via a
- The remote control password was invalid: {data!r}
- Remote control is not enabled, remember to use allow_remote_
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/b36bc889464fa3ed.
Report an issue: GitHub.