wavetermdev/waveterm · error
%s: is a directory
Error message
%s: is a directory
What it means
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.
Source
Thrown at cmd/wsh/cmd/wshcmd-file.go:339
return nil
}
func checkFileSize(path string, maxSize int64) (*wshrpc.FileInfo, error) {
fileData := wshrpc.FileData{
Info: &wshrpc.FileInfo{
Path: path}}
info, err := wshclient.FileInfoCommand(RpcClient, fileData, &wshrpc.RpcOpts{Timeout: fileTimeout})
err = convertNotFoundErr(err)
if err != nil {
return nil, fmt.Errorf("getting file info: %w", err)
}
if info.NotFound {
return nil, fmt.Errorf("%s: no such file", path)
}
if info.IsDir {
return nil, fmt.Errorf("%s: is a directory", path)
}
if info.Size > maxSize {
return nil, fmt.Errorf("file size (%d bytes) exceeds maximum of %d bytes", info.Size, maxSize)
}
return info, nil
}
func fileCpRun(cmd *cobra.Command, args []string) error {
src, dst := args[0], args[1]
merge, err := cmd.Flags().GetBool("merge")
if err != nil {
return err
}
force, err := cmd.Flags().GetBool("force")
if err != nil {
return err
}
View on GitHub (pinned to a4447c1563)
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
Example fix
// before wsh file cp [block] ./mydir @ # error: mydir is a directory // after tar czf mydir.tgz mydir && wsh file cp [block] ./mydir.tgz @
Defensive patterns
Strategy: type-guard
Validate before calling
info, err := wshclient.FileInfoCommand(RpcClient, fileData, &wshrpc.RpcOpts{Timeout: fileTimeout})
if err == nil && info.IsDir {
return fmt.Errorf("%s is a directory; cp/mv only supports regular files", path)
} Type guard
func isRegularFile(info *wshrpc.FileInfo) bool {
return info != nil && !info.IsDir && !info.NotFound
} Prevention
- 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
When it happens
Trigger: '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).
Common situations: 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.
Related errors
- file size (%d bytes) exceeds maximum of %d bytes
- Image too large (>5MB)
- Unsupported or invalid image type: ${blob.type}
- Invalid CSS color: ${String(color)}
- Invalid CSS color: ${color}
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/3a373f12d8702ad8.
Report an issue: GitHub.