{"record":{"id":"51ff3ed0b3944ca2","repo":"kovidgoyal/kitty","slug":"eisdir","errorCode":"EISDIR","errorMessage":"Cannot write data to a directory entry","messagePattern":"Cannot write data to a directory entry","errorType":"error_code","errorClass":"TransmissionError","httpStatus":null,"severity":"error","filePath":"kitty/file_transmission.py","lineNumber":515,"sourceCode":"            else:\n                os.chmod(self.name, self.permissions)\n        if self.mtime != FileTransmissionCommand.mtime:\n            if is_symlink:\n                with suppress(NotImplementedError):\n                    os.utime(self.name, ns=(self.mtime, self.mtime), follow_symlinks=False)\n            else:\n                os.utime(self.name, ns=(self.mtime, self.mtime))\n\n    def unlink_existing_if_needed(self, force: bool = False) -> None:\n        if force or self.needs_unlink:\n            with suppress(FileNotFoundError):\n                os.unlink(self.name)\n            self.existing_stat = None\n            self.needs_unlink = False\n\n    def write_data(self, all_files: dict[str, 'DestFile'], data: bytes | memoryview, is_last: bool) -> None:\n        if self.ftype is FileType.directory:\n            raise TransmissionError(code=ErrorCode.EISDIR, file_id=self.file_id, msg='Cannot write data to a directory entry')\n        if self.closed:\n            raise TransmissionError(file_id=self.file_id, msg='Cannot write to a closed file')\n        if self.ftype in (FileType.symlink, FileType.link):\n            self.link_target += data\n            self.bytes_written += len(data)\n            if is_last:\n                lt = self.link_target.decode('utf-8', 'replace')\n                base = self.make_parent_dirs()\n                self.unlink_existing_if_needed(force=True)\n                if lt.startswith('fid:'):\n                    lt = all_files[lt[4:]].name\n                    if self.ftype is FileType.symlink:\n                        lt = os.path.relpath(lt, os.path.dirname(self.name))\n                elif lt.startswith('fid_abs:'):\n                    lt = all_files[lt[8:]].name\n                elif lt.startswith('path:'):\n                    lt = lt[5:]\n                    if not os.path.isabs(lt) and self.ftype is FileType.link:","sourceCodeStart":497,"sourceCodeEnd":533,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kitty/file_transmission.py#L497-L533","documentation":"DestFile.write_data refuses to append payload bytes to an entry whose ftype is FileType.directory, because directories have no file content. It raises TransmissionError with code EISDIR, mirroring the OS errno.","triggerScenarios":"A peer sends an 'action=data' (or end_data) command for a file_id previously started with a directory entry — e.g. buggy sender that always streams data even for dir entries.","commonSituations":"Directory-transfer senders that emit an empty data frame for every spec including directories; version mismatch between sender/receiver implementations; hand-crafted test sequences.","solutions":["Fix the sender to skip data actions for directory entries (only send file/end_data for regular files).","If hand-writing the protocol, ensure action=data is only used after a file-type start with content."],"exampleFix":"# before\nif spec.is_dir:\n    pass  # still falls through to send data\n# after\nif spec.is_dir:\n    continue  # no data frames for directories","handlingStrategy":"validation","validationCode":"if entry.ftype is FileType.directory:\n    return  # skip data phase for dirs","typeGuard":"def accepts_data(ftype) -> bool:\n    return ftype is not FileType.directory","tryCatchPattern":"try:\n    add_data(ftc)\nexcept TransmissionError as e:\n    if e.code is ErrorCode.EISDIR: log.warning('ignoring data for directory %s', e.file_id)\n    else: raise","preventionTips":["Senders: never emit data frames for directory specs.","Test directory transfers explicitly."],"tags":["kitty","file-transfer","eisdir"],"backgroundTag":"write-to-directory","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}