{"record":{"id":"dc8972adc278c1a6","repo":"kovidgoyal/kitty","slug":"no-files-to-copy-specified","errorCode":null,"errorMessage":"No files to copy specified","messagePattern":"No files to copy specified","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kittens/ssh/config.go","lineNumber":236,"sourceCode":"func ParseCopyInstruction(spec string) (ans []*CopyInstruction, err error) {\n\targs, err := shlex.Split(\"copy \" + spec)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\topts, args, err := parse_copy_args(args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlocations := make([]string, 0, len(args))\n\tfor _, arg := range args {\n\t\tlocs, err := resolve_file_spec(arg, opts.Glob)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tlocations = append(locations, locs...)\n\t}\n\tif len(locations) == 0 {\n\t\treturn nil, fmt.Errorf(\"No files to copy specified\")\n\t}\n\tif len(locations) > 1 && opts.Dest != \"\" {\n\t\treturn nil, fmt.Errorf(\"Specifying a remote location with more than one file is not supported\")\n\t}\n\thome := paths_ctx.HomePath()\n\tans = make([]*CopyInstruction, 0, len(locations))\n\tfor _, loc := range locations {\n\t\tci := CopyInstruction{local_path: loc, exclude_patterns: opts.Exclude}\n\t\tif opts.SymlinkStrategy != \"preserve\" {\n\t\t\tci.local_path, err = filepath.EvalSymlinks(loc)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"Failed to resolve symlinks in %#v with error: %w\", loc, err)\n\t\t\t}\n\t\t}\n\t\tif opts.SymlinkStrategy == \"resolve\" {\n\t\t\tci.arcname = get_arcname(ci.local_path, opts.Dest, home)\n\t\t} else {\n\t\t\tci.arcname = get_arcname(loc, opts.Dest, home)","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kittens/ssh/config.go#L218-L254","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the glob/pattern actually matches files: ls <pattern> in the same shell","Guard in scripts: only invoke the kitten when the file list is non-empty","Fix typos or stale paths in the copy specification"],"exampleFix":"# before\nkitty +kitten ssh --copy \"logs/*.log\" user@host\n# after\nls logs/*.log >/dev/null 2>&1 && kitty +kitten ssh --copy \"logs/*.log\" user@host","handlingStrategy":"validation","validationCode":"matches, _ := filepath.Glob(pattern)\nif len(matches) == 0 {\n    // skip the copy call entirely\n}","typeGuard":null,"tryCatchPattern":"if err := ParseCopyInstruction(opts); err != nil && strings.Contains(err.Error(), \"No files to copy\") {\n    // benign: nothing to transfer\n    return nil\n}","preventionTips":["Expand globs in scripts and check length before invoking","Treat empty expansion as a skip, not an error, in automation"],"tags":["ssh-kitten","copy","empty-input","validation"],"backgroundTag":"empty-file-glob-match","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}