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
- Drop the destination and let the kitten derive arcnames, or copy files one at a time
- Use a single tar/archive source instead of multiple loose files
- 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
- Never pair a multi-file glob with an explicit remote destination
- Check expanded file count in wrappers before calling the kitten
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
- No files to copy specified
- Cannot specify both name and size
- Cannot read from: %s with error: %w
- Failed to resolve symlinks in %#v with error: %w
- Incorrect owner on SHM file
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/66f17b50fd613870.
Report an issue: GitHub.