kovidgoyal/kitty · error · TransmissionError

Unknown link target type

Error message

Unknown link target type

What it means

For FileType.symlink/link entries, the accumulated link target must start with a scheme prefix ('file:', 'path:', etc.); an unrecognized prefix raises TransmissionError('Unknown link target type').

Source

Thrown at kitty/file_transmission.py:537

            self.link_target += data
            self.bytes_written += len(data)
            if is_last:
                lt = self.link_target.decode('utf-8', 'replace')
                base = self.make_parent_dirs()
                self.unlink_existing_if_needed(force=True)
                if lt.startswith('fid:'):
                    lt = all_files[lt[4:]].name
                    if self.ftype is FileType.symlink:
                        lt = os.path.relpath(lt, os.path.dirname(self.name))
                elif lt.startswith('fid_abs:'):
                    lt = all_files[lt[8:]].name
                elif lt.startswith('path:'):
                    lt = lt[5:]
                    if not os.path.isabs(lt) and self.ftype is FileType.link:
                        lt = os.path.join(base, lt)
                    lt = lt.replace('/', os.sep)
                else:
                    raise TransmissionError(msg='Unknown link target type', file_id=self.file_id)
                if self.ftype is FileType.symlink:
                    os.symlink(lt, self.name)
                else:
                    os.link(lt, self.name)
                self.close()
                self.apply_metadata(is_symlink=True)
        elif self.ftype is FileType.regular:
            decompressed = self.decompressor(data, is_last=is_last)
            if self.actual_file is None:
                self.make_parent_dirs()
                self.unlink_existing_if_needed()
                flags = os.O_RDWR | os.O_CREAT | os.O_TRUNC | getattr(os, 'O_CLOEXEC', 0) | getattr(os, 'O_BINARY', 0) | getattr(os, 'O_NOFOLLOW', 0)
                self.actual_file = open(os.open(self.name, flags, self.permissions), mode='r+b', closefd=True)
            af = self.actual_file
            if decompressed or is_last:
                af.write(decompressed)
                self.bytes_written = af.tell()
            if is_last:

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Prefix the target with a supported scheme, e.g. 'path:relative/path' or 'file:...'.
  2. Align sender and receiver kitty versions so the supported prefix set matches.

Example fix

# before
target = b'/etc/hostname'
# after
target = b'path:/etc/hostname'
Defensive patterns

Strategy: validation

Validate before calling

KNOWN_PREFIXES = ('file:', 'path:')
assert any(target.startswith(p) for p in KNOWN_PREFIXES), target

Type guard

def is_valid_link_target(t: bytes) -> bool:
    return any(t.startswith(p.encode()) for p in ('file:', 'path:'))

Try / catch

try:
    link_entry.write_data(files, target, True)
except TransmissionError as e:
    if 'Unknown link target' in e.msg: fix_prefix_and_retry()
    else: raise

Prevention

When it happens

Trigger: write_data reaches is_last for a symlink/link DestFile whose decoded link_target does not start with any known prefix — sender used a raw target or an unsupported scheme.

Common situations: Custom senders writing bare paths as the target; protocol version drift adding/removing target schemes; hand-built test payloads.

Related errors


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