wavetermdev/waveterm · error
remote command failed: %w (stderr: %s)
Error message
remote command failed: %w (stderr: %s)
What it means
CpWshToRemote waits for the remote command process to finish via genconn.ProcessContextWait. If the remote process exits nonzero or is killed (including by context cancellation), the error is wrapped along with everything the command wrote to stderr.
Source
Thrown at pkg/remote/connutil.go:154
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)
return strings.Contains(shellBase, "powershell") || strings.Contains(shellBase, "pwsh")
}
func NormalizeConfigPattern(pattern string) string {
userName, err := WaveSshConfigUserSettings().GetStrict(pattern, "User")
if err != nil || userName == "" {
log.Printf("warning: error parsing username of %s for conn dropdown: %v", pattern, err)View on GitHub (pinned to a4447c1563)
Solutions
- Read the stderr text embedded in the error — it states the remote-side cause
- Fix remote destination permissions or choose a writable install path
- Stop the running remote wsh instance before overwriting the binary
- Retry; if caused by ctx cancellation, re-run with a longer/valid context
Example fix
// before
err := CpWshToRemote(ctx, conn, input, "/usr/local/bin/wsh") // permission denied in stderr
// after
dest := os.ExpandEnv("$HOME/.local/bin/wsh") // user-writable path
err := CpWshToRemote(ctx, conn, input, dest) Defensive patterns
Strategy: try-catch
Validate before calling
if ok, _ := remotePathWritable(ctx, conn, filepath.Dir(dest)); !ok {
return fmt.Errorf("destination dir %q not writable on remote", filepath.Dir(dest))
} Try / catch
var remoteCmdErr *RemoteCmdError
err := CpWshToRemote(ctx, conn, input, dest)
if errors.As(err, &remoteCmdErr) {
log.Errorf("remote stderr: %s", remoteCmdErr.Stderr) // diagnose from stderr
} Prevention
- Stop the running wsh binary before overwriting it
- Use a user-writable install path
- Set adequate context deadlines and surface ctx cancellation to users
When it happens
Trigger: UpdateWsh/InstallWsh copying wsh to a remote where the receiving command fails: wrong permissions on destination, context deadline exceeded, remote shell reporting an error, disk full.
Common situations: Destination directory not writable by the SSH user; remote filesystem full while writing the new wsh binary; user cancelled the operation; remote wsh refusing overwrite of a running binary (ETXTBSY-like behavior).
Related errors
- failed to start remote command: %w
- procinfo: process not found
- failed to start durable shell: %w
- failed to run app: %w
- failed to create process controller: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/366e42a1a623073c.
Report an issue: GitHub.