{"record":{"id":"4ea49d96319b524e","repo":"kovidgoyal/kitty","slug":"received-incomplete-data-for-clipboard","errorCode":null,"errorMessage":"Received incomplete data for clipboard","messagePattern":"Received incomplete data for clipboard","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kitty/clipboard.py","lineNumber":345,"sourceCode":"        if not self.currently_writing_mime:\n            self.mime_map[mime] = MimePos(self.tempfile.tell(), -1)\n            self.currently_writing_mime = mime\n        self.write_base64_data(data)\n\n    def flush_base64_data(self) -> None:\n        if self.currently_writing_mime:\n            incomplete = self.decoder.needs_more_data()\n            self.decoder.reset()\n            start = self.mime_map[self.currently_writing_mime][0]\n            self.mime_map[self.currently_writing_mime] = MimePos(start, self.tempfile.tell() - start)\n            self.currently_writing_mime = ''\n            if incomplete:\n                # the data is not padded to a multiple of four bytes. This is\n                # tolerated for the legacy OSC 52 protocol as it has no way to\n                # report errors to the client.\n                if self.protocol_type is ProtocolType.osc_5522:\n                    raise self.abort('Incomplete base64 data, missing padding bytes')\n                log_error('Received incomplete data for clipboard')\n\n    def write_base64_data(self, b: bytes | memoryview) -> None:\n        if not self.max_size_exceeded:\n            try:\n                decoded = self.decoder.decode(b)\n            except ValueError as e:\n                raise self.abort(f'Invalid base64 data: {e}') from e\n            if decoded:\n                self.tempfile.write(decoded)\n                if self.max_size > 0 and self.tempfile.tell() > self.max_size:\n                    log_error(f'Clipboard write request has more data than allowed by clipboard_max_size ({self.max_size} bytes), ignoring further data')\n                    self.max_size_exceeded = True\n\n    def data_for(self, mime: str = 'text/plain', offset: int = 0, size: int = -1) -> bytes:\n        start, full_size = self.mime_map[mime]\n        if size == -1:\n            size = full_size\n        return self.tempfile.read(start + offset, size)","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kitty/clipboard.py#L327-L363","documentation":"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.","triggerScenarios":"A terminal application sends OSC 52 with truncated/unpadded base64; flush_base64_data detects leftover bytes via the base64 decoder.","commonSituations":"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.","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"],"exampleFix":"# before (client)\nprintf '\\033]52;c;%s\\a' \"$b64\"   # b64 unpadded/truncated\n# after\nprintf '\\033]52;c;%s\\a' \"$(base64 -w0 \"$file\")\"","handlingStrategy":"validation","validationCode":"import base64\ndef valid_b64(s: str) -> bool:\n    try:\n        base64.b64decode(s + '=' * (-len(s) % 4), validate=True)\n        return True\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always emit padded base64 in OSC 52","Write the whole escape sequence in one write() call"],"tags":["kitty","clipboard","base64","osc52","terminal-protocol"],"backgroundTag":"base64-decode-invalid-input","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}