wavetermdev/waveterm · error

failed to start process: %w

Error message

failed to start process: %w

What it means

RunSimpleCommand calls proc.Start() to launch the prepared process; this error wraps any failure from starting it. The controller was created and both pipes were set up, so the failure is at exec/session-start time: the binary or shell was not found, working directory invalid, or the remote session rejected the exec request.

Source

Thrown at pkg/genconn/genconn.go:82

}

func RunSimpleCommand(ctx context.Context, client ShellClient, spec CommandSpec) (string, string, error) {
	proc, err := client.MakeProcessController(spec)
	if err != nil {
		return "", "", fmt.Errorf("failed to create process controller: %w", err)
	}

	stdout, err := proc.StdoutPipe()
	if err != nil {
		return "", "", fmt.Errorf("failed to get stdout pipe: %w", err)
	}
	stderr, err := proc.StderrPipe()
	if err != nil {
		return "", "", fmt.Errorf("failed to get stderr pipe: %w", err)
	}

	if err := proc.Start(); err != nil {
		return "", "", fmt.Errorf("failed to start process: %w", err)
	}

	stdoutBuf := syncbuf.MakeSyncBuffer()
	stderrBuf := syncbuf.MakeSyncBuffer()
	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		defer wg.Done()
		io.Copy(stdoutBuf, stdout)
	}()

	go func() {
		defer wg.Done()
		io.Copy(stderrBuf, stderr)
	}()

	runErr := ProcessContextWait(ctx, proc)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect the wrapped error: 'chdir ... no such file or directory' means fix CommandSpec.Cwd; 'fork/exec' resource errors mean check process/memory limits on the host.
  2. Verify Cwd exists on the target machine before running (ls via a prior command).
  3. For SSH 'request failed' errors, check sshd config (PermitUserShell / forced commands) and that the account has shell access.
  4. Check that the remote has a POSIX shell (sh) available, since BuildShellCommand wraps everything in sh -c.
  5. Retry after freeing resources if the cause is fork/EAGAIN under load.

Example fix

// before
spec := genconn.CommandSpec{Cmd: "deploy.sh", Cwd: "/opt/app"}
_, _, err := genconn.RunSimpleCommand(ctx, client, spec)
// after
cwd := "/opt/app"
if _, _, err := genconn.RunSimpleCommand(ctx, client, genconn.CommandSpec{Cmd: "test -d " + shellutil.HardQuote(cwd)}); err != nil {
    return fmt.Errorf("remote cwd %s missing: %w", cwd, err)
}
spec := genconn.CommandSpec{Cmd: "deploy.sh", Cwd: cwd}
_, _, err := genconn.RunSimpleCommand(ctx, client, spec)
Defensive patterns

Strategy: validation

Validate before calling

func validateSpec(ctx context.Context, client genconn.ShellClient, spec genconn.CommandSpec) error {
    check := fmt.Sprintf("test -d %s && command -v sh", shellutil.HardQuote(spec.Cwd))
    _, stderr, err := genconn.RunSimpleCommand(ctx, client, genconn.CommandSpec{Cmd: check})
    if err != nil {
        return fmt.Errorf("remote env invalid (stderr: %s): %w", stderr, err)
    }
    return nil
}

Try / catch

err := proc.Start() // or via RunSimpleCommand
if err != nil {
    var ee *exec.Error
    if errors.As(err, &ee) {
        return fmt.Errorf("binary %q not found on host", ee.Name)
    }
    if strings.Contains(err.Error(), "chdir") {
        return fmt.Errorf("cwd missing on host: %w", err)
    }
    return fmt.Errorf("start failed: %w", err)
}

Prevention

When it happens

Trigger: proc.Start() errors: 'sh' not found on the remote (unlikely) or command path invalid; exec: chdir to a nonexistent Cwd; SSH 'request failed: channel' errors when the server refuses exec; resource limits (fork failure, EAGAIN) on the host.

Common situations: CommandSpec.Cwd pointing to a directory that does not exist on the remote; running commands on an overloaded remote that cannot fork; SSH server with exec disabled or restricted shells rejecting the request.

Related errors


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