kovidgoyal/kitty · error · TransmissionError

The file_id {ftc.file_id} already exists

Error message

The file_id {ftc.file_id} already exists

What it means

The receiving side tracks in-flight transfers by file_id; start_file refuses to open a file_id that is already present in self.files, raising TransmissionError('The file_id ... already exists').

Source

Thrown at kitty/file_transmission.py:619

        self.pending_files_to_transmit_signature_of: Deque[tuple[PatchFile, str]] = deque()
        self.signature_pending_chunks: Deque[FileTransmissionCommand] = deque()

    @property
    def is_expired(self) -> bool:
        return monotonic() - self.last_activity_at > (60 * EXPIRE_TIME)

    def close(self) -> None:
        for x in self.files.values():
            x.close()
        self.files = {}

    def cancel(self) -> None:
        self.close()

    def start_file(self, ftc: FileTransmissionCommand) -> DestFile:
        self.last_activity_at = monotonic()
        if ftc.file_id in self.files:
            raise TransmissionError(
                msg=f'The file_id {ftc.file_id} already exists',
                file_id=ftc.file_id,
            )
        self.files[ftc.file_id] = df = DestFile(ftc)
        return df

    def add_data(self, ftc: FileTransmissionCommand) -> DestFile:
        self.last_activity_at = monotonic()
        df = self.files.get(ftc.file_id)
        if df is None:
            raise TransmissionError(file_id=ftc.file_id, msg='Cannot write to a file without first starting it')
        if df.failed:
            return df
        try:
            df.write_data(self.files, ftc.data, ftc.action is Action.end_data)
        except Exception:
            df.failed = True
            with suppress(Exception):

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Use unique file_ids per transfer (uuid or monotonic counter per session).
  2. Dedupe retries so the start frame is sent exactly once.
  3. If a transfer aborted, send a cancel/finish for the stale id before reusing it.

Example fix

# before
file_id = 'f'  # reused for every file
# after
import uuid
file_id = str(uuid.uuid4())
Defensive patterns

Strategy: validation

Validate before calling

if ftc.file_id in receiver.files:
    receiver.cancel(ftc.file_id)  # or reject before start

Try / catch

try:
    receiver.start_file(ftc)
except TransmissionError as e:
    if 'already exists' in e.msg: receiver.cancel(ftc); receiver.start_file(ftc)
    else: raise

Prevention

When it happens

Trigger: handle_receive_cmd receives two action=file commands with the same file_id before the first completes/end_data clears it — duplicated start frames or sender reusing ids in one session.

Common situations: Retry logic that resends the start command; senders generating ids with a weak counter that resets; concurrent transfers accidentally sharing id namespace.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/0974f495edee94db. Report an issue: GitHub.