kovidgoyal/kitty · warning
Received incomplete data for clipboard
Error message
Received incomplete data for clipboard
What it means
An OSC 52 clipboard write ended with base64 data whose length is not a multiple of 4. For the legacy OSC 52 protocol kitty tolerates it (no error channel) and logs this; for OSC 5522 it instead raises an abort sent back to the client.
Source
Thrown at kitty/clipboard.py:345
if not self.currently_writing_mime:
self.mime_map[mime] = MimePos(self.tempfile.tell(), -1)
self.currently_writing_mime = mime
self.write_base64_data(data)
def flush_base64_data(self) -> None:
if self.currently_writing_mime:
incomplete = self.decoder.needs_more_data()
self.decoder.reset()
start = self.mime_map[self.currently_writing_mime][0]
self.mime_map[self.currently_writing_mime] = MimePos(start, self.tempfile.tell() - start)
self.currently_writing_mime = ''
if incomplete:
# the data is not padded to a multiple of four bytes. This is
# tolerated for the legacy OSC 52 protocol as it has no way to
# report errors to the client.
if self.protocol_type is ProtocolType.osc_5522:
raise self.abort('Incomplete base64 data, missing padding bytes')
log_error('Received incomplete data for clipboard')
def write_base64_data(self, b: bytes | memoryview) -> None:
if not self.max_size_exceeded:
try:
decoded = self.decoder.decode(b)
except ValueError as e:
raise self.abort(f'Invalid base64 data: {e}') from e
if decoded:
self.tempfile.write(decoded)
if self.max_size > 0 and self.tempfile.tell() > self.max_size:
log_error(f'Clipboard write request has more data than allowed by clipboard_max_size ({self.max_size} bytes), ignoring further data')
self.max_size_exceeded = True
def data_for(self, mime: str = 'text/plain', offset: int = 0, size: int = -1) -> bytes:
start, full_size = self.mime_map[mime]
if size == -1:
size = full_size
return self.tempfile.read(start + offset, size)View on GitHub (pinned to 6d5d0c4406)
Solutions
- Update/fix the client app to send properly padded base64
- If it's your code, ensure the full OSC 52 sequence is written atomically and padded with '='
- Chunk boundaries must be multiples of 4 bytes except the final chunk
Example fix
# before (client) printf '\033]52;c;%s\a' "$b64" # b64 unpadded/truncated # after printf '\033]52;c;%s\a' "$(base64 -w0 "$file")"
Defensive patterns
Strategy: validation
Validate before calling
import base64
def valid_b64(s: str) -> bool:
try:
base64.b64decode(s + '=' * (-len(s) % 4), validate=True)
return True
except Exception:
return False Prevention
- Always emit padded base64 in OSC 52
- Write the whole escape sequence in one write() call
When it happens
Trigger: A terminal application sends OSC 52 with truncated/unpadded base64; flush_base64_data detects leftover bytes via the base64 decoder.
Common situations: Buggy terminal client apps (older tmux copy-mode scripts, custom ssh wrappers) that clip the escape sequence at a buffer boundary, often with large clipboards.
Related errors
- Invalid base64 encoded data from terminal with error: %w
- Ignoring OSC 52 clipboard write request as it is not valid b
- Received OSC %s packet from terminal with invalid base64 enc
- Malformed OSC 5522: could not decode a metadata value. Error
- Malformed OSC 5522: read request payload is not valid base64
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/4ea49d96319b524e.
Report an issue: GitHub.