wavetermdev/waveterm · error
cannot create destination file %q: %w
Error message
cannot create destination file %q: %w
What it means
After validating the source and resolving the destination path, the command opens the destination with os.OpenFile(O_CREATE|O_WRONLY|O_TRUNC, mode from source). This error wraps the OS-level failure to create or truncate that local destination file; the wrapped cause carries the exact reason (permissions, missing directory, disk full, etc.).
Source
Thrown at pkg/wshrpc/wshremote/wshremote_file.go:167
srcFileInfo, err := wshclient.RemoteFileInfoCommand(wshfs.RpcClient, srcConn.Path, &wshrpc.RpcOpts{Timeout: opts.Timeout, Route: wshutil.MakeConnectionRouteId(srcConn.Host)})
if err != nil {
return false, fmt.Errorf("cannot get info for source file %q: %w", data.SrcUri, err)
}
if srcFileInfo.IsDir {
return false, fmt.Errorf("copying directories is not supported")
}
if srcFileInfo.Size > RemoteFileTransferSizeLimit {
return false, fmt.Errorf("file %q size %d exceeds transfer limit of %d bytes", data.SrcUri, srcFileInfo.Size, RemoteFileTransferSizeLimit)
}
destFilePath, err := prepareDestForCopy(destPathCleaned, fspath.Base(srcConn.Path), destHasSlash, opts.Overwrite)
if err != nil {
return false, err
}
destFile, err := os.OpenFile(destFilePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, srcFileInfo.Mode)
if err != nil {
return false, fmt.Errorf("cannot create destination file %q: %w", destFilePath, err)
}
defer destFile.Close()
if wshfs.RpcClientRouteId == "" {
return false, fmt.Errorf("stream broker route id not available for file copy")
}
writerRouteId := wshutil.MakeConnectionRouteId(srcConn.Host)
reader, streamMeta := wshfs.RpcClient.StreamBroker.CreateStreamReader(wshfs.RpcClientRouteId, writerRouteId, 256*1024)
log.Printf("RemoteFileCopyCommand: readroute=%s writeroute=%s", streamMeta.ReaderRouteId, streamMeta.WriterRouteId)
defer reader.Close()
go func() {
<-readCtx.Done()
reader.Close()
}()
streamData := wshrpc.CommandRemoteFileStreamData{
Path: srcConn.Path,
StreamMeta: *streamMeta,
}View on GitHub (pinned to a4447c1563)
Solutions
- Ensure the destination directory exists (create it with os.MkdirAll or wsh mkdir before copying).
- Check write permissions on the destination directory and that destFilePath is not itself a directory.
- Read the wrapped cause (%w): errors.Is(err, fs.ErrNotExist) → create dir; fs.ErrPermission → fix perms; syscall.ENOSPC → free disk space.
- Choose a writable destination path (e.g. under the user's home) via ExpandHomeDir-aware URIs.
Example fix
// before
RemoteFileCopyCommand(ctx, wshrpc.CommandFileCopyData{SrcUri: src, DestUri: "/root/out/file.txt"})
// after
os.MkdirAll("/home/me/out", 0o755)
RemoteFileCopyCommand(ctx, wshrpc.CommandFileCopyData{SrcUri: src, DestUri: "file:///home/me/out/file.txt"}) Defensive patterns
Strategy: validation
Validate before calling
destDir := filepath.Dir(destPath)
if info, err := os.Stat(destDir); err != nil || !info.IsDir() {
return fmt.Errorf("destination dir %s missing", destDir)
}
if info, err := os.Stat(destPath); err == nil && info.IsDir() {
return fmt.Errorf("destination %s is a directory", destPath)
}
if err := unix.Access(destDir, unix.W_OK); err != nil {
return fmt.Errorf("no write permission on %s", destDir)
} Type guard
func destWritable(path string) bool {
d := filepath.Dir(path)
fi, err := os.Stat(d)
return err == nil && fi.IsDir() && unix.Access(d, unix.W_OK) == nil
} Try / catch
ok, err := RemoteFileCopyCommand(ctx, data)
if err != nil {
if strings.Contains(err.Error(), "cannot create destination file") {
var pe *fs.PathError
if errors.As(err, &pe) {
switch {
case errors.Is(pe, fs.ErrNotExist): os.MkdirAll(filepath.Dir(pe.Path), 0o755)
case errors.Is(pe, fs.ErrPermission): return fmt.Errorf("check permissions on %s", pe.Path)
}
}
}
return err
} Prevention
- Create the destination directory (MkdirAll) before copying.
- Ensure the destination path points to a file, not an existing directory.
- Verify write permissions and free disk space on the destination volume.
- Use home-relative destinations (~/...) so ExpandHomeDirSafe resolves to a writable path.
When it happens
Trigger: os.OpenFile(destFilePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, srcFileInfo.Mode) fails: destination directory does not exist, no write permission, destFilePath is itself a directory, or the filesystem is read-only/full.
Common situations: Copy destination URI points into a nonexistent directory; running the copy from a user without write access to the destination; destination path is an existing directory; disk quota exceeded.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- accessing file %s: %w
- reading directory %s: %w
- reading file %s: %w
- error creating listener at %v: %v
- getting file info: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/fe35339cad41742b.
Report an issue: GitHub.