kovidgoyal/kitty · warning

Specifying a remote location with more than one file is not

Error message

Specifying a remote location with more than one file is not supported

What it means

ParseCopyInstruction refuses to combine multiple source locations with an explicit destination arcname. When more than one file is resolved, the single destination name is ambiguous, so the kitten errors out rather than guessing.

Source

Thrown at kittens/ssh/config.go:239

		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)
		}
		ans = append(ans, &ci)
	}

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Drop the destination and let the kitten derive arcnames, or copy files one at a time
  2. Use a single tar/archive source instead of multiple loose files
  3. Double-check the glob isn't matching more than intended (quote and echo it)

Example fix

# before
kitty +kitten ssh --copy "a.txt b.txt myserver:archive.tar.gz" user@host
# after
kitty +kitten ssh --copy a.txt user@host
kitty +kitten ssh --copy b.txt user@host
Defensive patterns

Strategy: validation

Validate before calling

expanded, _ := filepath.Glob(pattern)
if len(expanded) > 1 && dest != "" {
    // copy one-by-one or drop dest
}

Prevention

When it happens

Trigger: Passing multiple files plus a remote destination, e.g. 'file1 file2 remote:dest' or a wildcard expanding to >1 file together with opts.Dest set.

Common situations: Users assuming remote copy mirrors scp's multi-file semantics; wildcards that unexpectedly expand to several files; scripts templating a dest onto variable-length file lists.

Related errors


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