kovidgoyal/kitty · warning

No files to copy specified

Error message

No files to copy specified

What it means

Returned by ParseCopyInstruction when the copy spec list resolves to zero local files. The kitten requires at least one file to transfer; an empty expansion (e.g. a glob matching nothing combined with no other sources) is rejected.

Source

Thrown at kittens/ssh/config.go:236

func ParseCopyInstruction(spec string) (ans []*CopyInstruction, err error) {
	args, err := shlex.Split("copy " + spec)
	if err != nil {
		return nil, err
	}
	opts, args, err := parse_copy_args(args)
	if err != nil {
		return nil, err
	}
	locations := make([]string, 0, len(args))
	for _, arg := range args {
		locs, err := resolve_file_spec(arg, opts.Glob)
		if err != nil {
			return nil, err
		}
		locations = append(locations, locs...)
	}
	if len(locations) == 0 {
		return nil, fmt.Errorf("No files to copy specified")
	}
	if len(locations) > 1 && opts.Dest != "" {
		return nil, fmt.Errorf("Specifying a remote location with more than one file is not supported")
	}
	home := paths_ctx.HomePath()
	ans = make([]*CopyInstruction, 0, len(locations))
	for _, loc := range locations {
		ci := CopyInstruction{local_path: loc, exclude_patterns: opts.Exclude}
		if opts.SymlinkStrategy != "preserve" {
			ci.local_path, err = filepath.EvalSymlinks(loc)
			if err != nil {
				return nil, fmt.Errorf("Failed to resolve symlinks in %#v with error: %w", loc, err)
			}
		}
		if opts.SymlinkStrategy == "resolve" {
			ci.arcname = get_arcname(ci.local_path, opts.Dest, home)
		} else {
			ci.arcname = get_arcname(loc, opts.Dest, home)

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Verify the glob/pattern actually matches files: ls <pattern> in the same shell
  2. Guard in scripts: only invoke the kitten when the file list is non-empty
  3. Fix typos or stale paths in the copy specification

Example fix

# before
kitty +kitten ssh --copy "logs/*.log" user@host
# after
ls logs/*.log >/dev/null 2>&1 && kitty +kitten ssh --copy "logs/*.log" user@host
Defensive patterns

Strategy: validation

Validate before calling

matches, _ := filepath.Glob(pattern)
if len(matches) == 0 {
    // skip the copy call entirely
}

Try / catch

if err := ParseCopyInstruction(opts); err != nil && strings.Contains(err.Error(), "No files to copy") {
    // benign: nothing to transfer
    return nil
}

Prevention

When it happens

Trigger: Calling ParseCopyInstruction with a CopyFiles spec whose patterns all expand to empty sets — e.g. a wildcard like 'src/*.log' when the directory has no matching files, or an empty opts.Files list.

Common situations: Build scripts that pass a generated file list which ends up empty on clean checkouts; typos in glob patterns that silently match nothing; CI jobs where an artifact step was skipped.

Related errors


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