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

  1. Ensure the destination directory exists (create it with os.MkdirAll or wsh mkdir before copying).
  2. Check write permissions on the destination directory and that destFilePath is not itself a directory.
  3. Read the wrapped cause (%w): errors.Is(err, fs.ErrNotExist) → create dir; fs.ErrPermission → fix perms; syscall.ENOSPC → free disk space.
  4. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/fe35339cad41742b. Report an issue: GitHub.