wavetermdev/waveterm · error

failed to copy data: %w

Error message

failed to copy data: %w

What it means

Inside CpWshToRemote a goroutine io.Copy's the local input into the remote command's stdin. Any copy failure other than io.EOF is wrapped with this message and surfaced after the process wait completes.

Source

Thrown at pkg/remote/connutil.go:147

	}
	stdin, err := genCmd.StdinPipe()
	if err != nil {
		return fmt.Errorf("failed to get stdin pipe: %w", err)
	}
	defer stdin.Close()
	stderrBuf, err := genconn.MakeStderrSyncBuffer(genCmd)
	if err != nil {
		return fmt.Errorf("failed to get stderr pipe: %w", err)
	}
	if err := genCmd.Start(); err != nil {
		return fmt.Errorf("failed to start remote command: %w", err)
	}
	copyDone := make(chan error, 1)
	go func() {
		defer close(copyDone)
		defer stdin.Close()
		if _, err := io.Copy(stdin, input); err != nil && err != io.EOF {
			copyDone <- fmt.Errorf("failed to copy data: %w", err)
		} else {
			copyDone <- nil
		}
	}()
	procErr := genconn.ProcessContextWait(ctx, genCmd)
	if procErr != nil {
		return fmt.Errorf("remote command failed: %w (stderr: %s)", procErr, stderrBuf.String())
	}
	copyErr := <-copyDone
	if copyErr != nil {
		return fmt.Errorf("failed to copy data: %w (stderr: %s)", copyErr, stderrBuf.String())
	}
	return nil
}

func IsPowershell(shellPath string) bool {
	// get the base path, and then check contains
	shellBase := filepath.Base(shellPath)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Retry the operation after confirming the remote connection is stable
  2. Check remote stderr (this variant has no stderr suffix, so it likely failed before process wait) and reconnect if the channel closed
  3. Verify the local input source is readable for the whole transfer
  4. Use a matching wsh version on both ends

Example fix

// before
f, _ := os.Open(binPath)
err := CpWshToRemote(ctx, conn, f, dest)
// after
f, err := os.Open(binPath)
if err != nil { return err }
defer f.Close()
if fi, statErr := f.Stat(); statErr != nil || !fi.Mode().IsRegular() {
    return fmt.Errorf("invalid input file")
}
err = CpWshToRemote(ctx, conn, f, dest)
Defensive patterns

Strategy: try-catch

Validate before calling

fi, err := input.Stat()
if err != nil || !fi.Mode().IsRegular() {
    return fmt.Errorf("input must be a readable regular file")
}

Try / catch

err := CpWshToRemote(ctx, conn, input, dest)
if err != nil && strings.Contains(err.Error(), "failed to copy data") {
    // check input source integrity, then retry once
    input.Seek(0, io.Start); err = CpWshToRemote(ctx, conn, input, dest)
}

Prevention

When it happens

Trigger: The local reader (input) errors mid-stream, or the remote stdin pipe closes prematurely (remote process died before consuming all data) during UpdateWsh/InstallWsh.

Common situations: Remote wsh process crashed or was killed mid-transfer; network interruption breaking the SSH channel; local file being read changed/vanished during copy.

Related errors


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