{"record":{"id":"461004e652729916","repo":"wavetermdev/waveterm","slug":"failed-to-copy-data-w","errorCode":null,"errorMessage":"failed to copy data: %w","messagePattern":"failed to copy data: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/remote/connutil.go","lineNumber":147,"sourceCode":"\t}\n\tstdin, err := genCmd.StdinPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get stdin pipe: %w\", err)\n\t}\n\tdefer stdin.Close()\n\tstderrBuf, err := genconn.MakeStderrSyncBuffer(genCmd)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get stderr pipe: %w\", err)\n\t}\n\tif err := genCmd.Start(); err != nil {\n\t\treturn fmt.Errorf(\"failed to start remote command: %w\", err)\n\t}\n\tcopyDone := make(chan error, 1)\n\tgo func() {\n\t\tdefer close(copyDone)\n\t\tdefer stdin.Close()\n\t\tif _, err := io.Copy(stdin, input); err != nil && err != io.EOF {\n\t\t\tcopyDone <- fmt.Errorf(\"failed to copy data: %w\", err)\n\t\t} else {\n\t\t\tcopyDone <- nil\n\t\t}\n\t}()\n\tprocErr := genconn.ProcessContextWait(ctx, genCmd)\n\tif procErr != nil {\n\t\treturn fmt.Errorf(\"remote command failed: %w (stderr: %s)\", procErr, stderrBuf.String())\n\t}\n\tcopyErr := <-copyDone\n\tif copyErr != nil {\n\t\treturn fmt.Errorf(\"failed to copy data: %w (stderr: %s)\", copyErr, stderrBuf.String())\n\t}\n\treturn nil\n}\n\nfunc IsPowershell(shellPath string) bool {\n\t// get the base path, and then check contains\n\tshellBase := filepath.Base(shellPath)","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/remote/connutil.go#L129-L165","documentation":"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.","triggerScenarios":"The local reader (input) errors mid-stream, or the remote stdin pipe closes prematurely (remote process died before consuming all data) during UpdateWsh/InstallWsh.","commonSituations":"Remote wsh process crashed or was killed mid-transfer; network interruption breaking the SSH channel; local file being read changed/vanished during copy.","solutions":["Retry the operation after confirming the remote connection is stable","Check remote stderr (this variant has no stderr suffix, so it likely failed before process wait) and reconnect if the channel closed","Verify the local input source is readable for the whole transfer","Use a matching wsh version on both ends"],"exampleFix":"// before\nf, _ := os.Open(binPath)\nerr := CpWshToRemote(ctx, conn, f, dest)\n// after\nf, err := os.Open(binPath)\nif err != nil { return err }\ndefer f.Close()\nif fi, statErr := f.Stat(); statErr != nil || !fi.Mode().IsRegular() {\n    return fmt.Errorf(\"invalid input file\")\n}\nerr = CpWshToRemote(ctx, conn, f, dest)","handlingStrategy":"try-catch","validationCode":"fi, err := input.Stat()\nif err != nil || !fi.Mode().IsRegular() {\n    return fmt.Errorf(\"input must be a readable regular file\")\n}","typeGuard":null,"tryCatchPattern":"err := CpWshToRemote(ctx, conn, input, dest)\nif err != nil && strings.Contains(err.Error(), \"failed to copy data\") {\n    // check input source integrity, then retry once\n    input.Seek(0, io.Start); err = CpWshToRemote(ctx, conn, input, dest)\n}","preventionTips":["Open input files fully before transfer; avoid streaming from unstable sources","Don't mutate or delete the input during copy","Keep SSH sessions alive; avoid aggressive idle timeouts"],"tags":["go","io","stream"],"backgroundTag":"stream-copy-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}