kovidgoyal/kitty · error · SystemExit

This should be run as kitten transfer

Error message

This should be run as kitten transfer

What it means

The transfer kitten's main() unconditionally raises SystemExit('This should be run as kitten transfer'). Like other kittens, the module's real entry points are wired up by kitty's kitten runner (see the '__doc__'/CompletionSpec branch); the __main__ branch is only a guard telling you to use the proper launcher.

Source

Thrown at kittens/transfer/main.py:124


--confirm-paths -c
type=bool-set
Before actually transferring files, show a mapping of local file names to remote
file names and ask for confirmation.


--transmit-deltas -x
type=bool-set
If a file on the receiving side already exists, use the rsync algorithm to
update it to match the file on the sending side, potentially saving lots of
bandwidth and also automatically resuming partial transfers. Note that this will
actually degrade performance on fast links or with small files, so use with care.
"""


def main(args: list[str]) -> None:
    raise SystemExit('This should be run as kitten transfer')


if __name__ == '__main__':
    main(sys.argv)
elif __name__ == '__doc__':
    from kitty.simple_cli_definitions import CompletionSpec

    cd = sys.cli_docs  # type: ignore
    cd['usage'] = usage
    cd['options'] = option_text
    cd['help_text'] = help_text
    cd['short_desc'] = 'Transfer files easily over the TTY device'
    cd['args_completion'] = CompletionSpec.from_string('type:file group:"Files"')

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Use `kitten transfer [options] src dest` from within kitty (see `kitten transfer --help` for hosts, resume, compression options).
  2. For programmatic use, invoke via subprocess `['kitten', 'transfer', ...]` rather than importing main().
  3. In tests, target the transfer module's helper functions, never main().

Example fix

# before
python kittens/transfer/main.py  # SystemExit: This should be run as kitten transfer

# after
kitten transfer --compress host:/remote/file local_copy
Defensive patterns

Strategy: fallback

Validate before calling

import shutil, subprocess

def transfer(src: str, dst: str, *opts: str) -> int:
    if shutil.which('kitten'):
        return subprocess.call(['kitten', 'transfer', *opts, src, dst])
    return subprocess.call(['scp', src, dst])  # fallback outside kitty

Prevention

When it happens

Trigger: Executing kittens/transfer/main.py with python directly, or importing it and calling main(). Correct usage is `kitten transfer ...` (file transfer between machines, optionally with resume/compression) inside kitty.

Common situations: Trying to script transfers by running the kitten file standalone; IDE/debugger run configurations on the file; copy-pasting the module into another project expecting it to be self-contained.

Related errors


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