{"record":{"id":"cc4395458626a215","repo":"kovidgoyal/kitty","slug":"cannot-write-to-a-file-without-first-starting-it","errorCode":null,"errorMessage":"Cannot write to a file without first starting it","messagePattern":"Cannot write to a file without first starting it","errorType":"exception","errorClass":"TransmissionError","httpStatus":null,"severity":"error","filePath":"kitty/file_transmission.py","lineNumber":630,"sourceCode":"\n    def cancel(self) -> None:\n        self.close()\n\n    def start_file(self, ftc: FileTransmissionCommand) -> DestFile:\n        self.last_activity_at = monotonic()\n        if ftc.file_id in self.files:\n            raise TransmissionError(\n                msg=f'The file_id {ftc.file_id} already exists',\n                file_id=ftc.file_id,\n            )\n        self.files[ftc.file_id] = df = DestFile(ftc)\n        return df\n\n    def add_data(self, ftc: FileTransmissionCommand) -> DestFile:\n        self.last_activity_at = monotonic()\n        df = self.files.get(ftc.file_id)\n        if df is None:\n            raise TransmissionError(file_id=ftc.file_id, msg='Cannot write to a file without first starting it')\n        if df.failed:\n            return df\n        try:\n            df.write_data(self.files, ftc.data, ftc.action is Action.end_data)\n        except Exception:\n            df.failed = True\n            with suppress(Exception):\n                df.close()\n            raise\n        return df\n\n    def commit(self, send_os_error: Callable[[OSError, str, 'ActiveReceive', str], None]) -> None:\n        directories = sorted((df for df in self.files.values() if df.ftype is FileType.directory), key=lambda x: len(x.name), reverse=True)\n        for df in directories:\n            with suppress(OSError):\n                # we ignore failures to apply directory metadata as we have already sent an OK for the dir\n                df.apply_metadata()\n","sourceCodeStart":612,"sourceCodeEnd":648,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kitty/file_transmission.py#L612-L648","documentation":"add_data looks up the DestFile by ftc.file_id; if no prior action=file/start created it, there is nothing to write to and it raises TransmissionError('Cannot write to a file without first starting it').","triggerScenarios":"Sending action=data for a file_id never started in this session, or after the receiver was reset/cleared — commonly a lost or dropped start frame.","commonSituations":"Escape-sequence start frame swallowed by a pager/multiplexer; sender state reset mid-transfer; hand-crafted sequences skipping the start step.","solutions":["Always begin each file with action=file (start) before any data frames.","If transfers may be interrupted, restart the whole transfer rather than resuming mid-stream.","Test the pipeline with kitty alone (no tmux/screen) to rule out sequence loss."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"assert ftc.file_id in receiver.files, f'not started: {ftc.file_id}'","typeGuard":null,"tryCatchPattern":"try:\n    receiver.add_data(ftc)\nexcept TransmissionError as e:\n    if 'without first starting' in e.msg: restart_transfer()\n    else: raise","preventionTips":["Always send action=file first in a session.","Avoid multiplexers that can drop OSC sequences during transfers."],"tags":["kitty","file-transfer","ordering"],"backgroundTag":"operation-before-initialization","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}