{"record":{"id":"3a373f12d8702ad8","repo":"wavetermdev/waveterm","slug":"s-is-a-directory","errorCode":null,"errorMessage":"%s: is a directory","messagePattern":"(.+?): is a directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/wsh/cmd/wshcmd-file.go","lineNumber":339,"sourceCode":"\n\treturn nil\n}\n\nfunc checkFileSize(path string, maxSize int64) (*wshrpc.FileInfo, error) {\n\tfileData := wshrpc.FileData{\n\t\tInfo: &wshrpc.FileInfo{\n\t\t\tPath: path}}\n\n\tinfo, err := wshclient.FileInfoCommand(RpcClient, fileData, &wshrpc.RpcOpts{Timeout: fileTimeout})\n\terr = convertNotFoundErr(err)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting file info: %w\", err)\n\t}\n\tif info.NotFound {\n\t\treturn nil, fmt.Errorf(\"%s: no such file\", path)\n\t}\n\tif info.IsDir {\n\t\treturn nil, fmt.Errorf(\"%s: is a directory\", path)\n\t}\n\tif info.Size > maxSize {\n\t\treturn nil, fmt.Errorf(\"file size (%d bytes) exceeds maximum of %d bytes\", info.Size, maxSize)\n\t}\n\treturn info, nil\n}\n\nfunc fileCpRun(cmd *cobra.Command, args []string) error {\n\tsrc, dst := args[0], args[1]\n\tmerge, err := cmd.Flags().GetBool(\"merge\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tforce, err := cmd.Flags().GetBool(\"force\")\n\tif err != nil {\n\t\treturn err\n\t}\n","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/cmd/wsh/cmd/wshcmd-file.go#L321-L357","documentation":"checkFileSize rejects directory sources with '%s: is a directory' — the cp/mv size pre-check only supports regular files, since it transfers file contents under the size cap. If the resolved source path is a directory (info.IsDir), the command fails before any transfer.","triggerScenarios":"'wsh file cp <dir> <dst>' or 'wsh file mv <dir> <dst>' where the source path resolves to a directory on the remote (e.g. a directory named like the intended file, or a trailing-slash/wildcard resolving to a dir).","commonSituations":"Trying to cp/mv a whole directory with a command that only handles files; glob or tab-completion resolving to the directory instead of the file; assuming recursive copy is supported.","solutions":["Pass the individual files inside the directory instead of the directory itself","Archive the directory first (tar/zip) and copy the archive as a single file","Check the path with 'wsh file info' to confirm it is a regular file before cp/mv"],"exampleFix":"// before\nwsh file cp [block] ./mydir @            # error: mydir is a directory\n// after\ntar czf mydir.tgz mydir && wsh file cp [block] ./mydir.tgz @","handlingStrategy":"type-guard","validationCode":"info, err := wshclient.FileInfoCommand(RpcClient, fileData, &wshrpc.RpcOpts{Timeout: fileTimeout})\nif err == nil && info.IsDir {\n    return fmt.Errorf(\"%s is a directory; cp/mv only supports regular files\", path)\n}","typeGuard":"func isRegularFile(info *wshrpc.FileInfo) bool {\n    return info != nil && !info.IsDir && !info.NotFound\n}","tryCatchPattern":null,"preventionTips":["Check info.IsDir before cp/mv and handle directories by archiving or per-file copies","Beware globs/completions resolving to directories","Remember wsh file cp/mv is not recursive"],"tags":["directory","cp","mv","validation"],"backgroundTag":"unsupported-operation-target","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}